From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- .../ShellPkg/Application/AcpiViewApp/AcpiViewApp.c | 40 + .../Application/AcpiViewApp/AcpiViewApp.inf | 34 + .../Application/AcpiViewApp/AcpiViewApp.uni | 122 + .../ShellPkg/Application/Shell/ConsoleLogger.c | 1237 +++++ .../ShellPkg/Application/Shell/ConsoleLogger.h | 317 ++ .../ShellPkg/Application/Shell/ConsoleWrappers.c | 508 ++ .../ShellPkg/Application/Shell/ConsoleWrappers.h | 74 + .../Application/Shell/FileHandleInternal.h | 59 + .../Application/Shell/FileHandleWrappers.c | 2154 ++++++++ .../Application/Shell/FileHandleWrappers.h | 87 + .../Firmware/ShellPkg/Application/Shell/Shell.c | 3183 +++++++++++ .../Firmware/ShellPkg/Application/Shell/Shell.h | 390 ++ .../Firmware/ShellPkg/Application/Shell/Shell.inf | 105 + .../Firmware/ShellPkg/Application/Shell/Shell.uni | 52 + .../ShellPkg/Application/Shell/ShellEnvVar.c | 572 ++ .../ShellPkg/Application/Shell/ShellEnvVar.h | 282 + .../ShellPkg/Application/Shell/ShellManParser.c | 757 +++ .../ShellPkg/Application/Shell/ShellManParser.h | 78 + .../Application/Shell/ShellParametersProtocol.c | 1414 +++++ .../Application/Shell/ShellParametersProtocol.h | 211 + .../ShellPkg/Application/Shell/ShellProtocol.c | 3848 +++++++++++++ .../ShellPkg/Application/Shell/ShellProtocol.h | 938 ++++ .../ShellPkg/Application/ShellCTestApp/README.txt | 5 + .../Application/ShellCTestApp/ShellCTestApp.c | 45 + .../Application/ShellCTestApp/ShellCTestApp.inf | 34 + .../Application/ShellCTestApp/TestArgv.log | Bin 0 -> 3320 bytes .../Application/ShellCTestApp/TestArgv.nsh | 58 + .../ShellPkg/Application/ShellExecTestApp/SA.c | 32 + .../ShellPkg/Application/ShellExecTestApp/SA.inf | 36 + .../ShellSortTestApp/ShellSortTestApp.c | 77 + .../ShellSortTestApp/ShellSortTestApp.inf | 37 + .../ShellPkg/DynamicCommand/DpDynamicCommand/Dp.c | 966 ++++ .../ShellPkg/DynamicCommand/DpDynamicCommand/Dp.h | 140 + .../DynamicCommand/DpDynamicCommand/Dp.uni | 128 + .../DynamicCommand/DpDynamicCommand/DpApp.c | 47 + .../DynamicCommand/DpDynamicCommand/DpApp.inf | 64 + .../DpDynamicCommand/DpDynamicCommand.c | 125 + .../DpDynamicCommand/DpDynamicCommand.inf | 68 + .../DynamicCommand/DpDynamicCommand/DpInternal.h | 315 ++ .../DynamicCommand/DpDynamicCommand/DpTrace.c | 904 +++ .../DynamicCommand/DpDynamicCommand/DpUtilities.c | 422 ++ .../DynamicCommand/DpDynamicCommand/Literals.c | 22 + .../DynamicCommand/DpDynamicCommand/Literals.h | 26 + .../DynamicCommand/HttpDynamicCommand/Http.c | 1905 +++++++ .../DynamicCommand/HttpDynamicCommand/Http.h | 92 + .../DynamicCommand/HttpDynamicCommand/Http.uni | 117 + .../DynamicCommand/HttpDynamicCommand/HttpApp.c | 61 + .../DynamicCommand/HttpDynamicCommand/HttpApp.inf | 57 + .../HttpDynamicCommand/HttpDynamicCommand.c | 137 + .../HttpDynamicCommand/HttpDynamicCommand.inf | 62 + .../DynamicCommand/TftpDynamicCommand/Tftp.c | 1129 ++++ .../DynamicCommand/TftpDynamicCommand/Tftp.h | 69 + .../DynamicCommand/TftpDynamicCommand/Tftp.uni | 94 + .../DynamicCommand/TftpDynamicCommand/TftpApp.c | 48 + .../DynamicCommand/TftpDynamicCommand/TftpApp.inf | 55 + .../TftpDynamicCommand/TftpDynamicCommand.c | 126 + .../TftpDynamicCommand/TftpDynamicCommand.inf | 60 + .../ShellPkg/Include/Guid/ShellAliasGuid.h | 19 + .../ShellPkg/Include/Guid/ShellEnvironment2Ext.h | 19 + .../ShellPkg/Include/Guid/ShellLibHiiGuid.h | 85 + .../Firmware/ShellPkg/Include/Guid/ShellMapGuid.h | 19 + .../ShellPkg/Include/Guid/ShellPkgTokenSpace.h | 19 + .../ShellPkg/Include/Guid/ShellVariableGuid.h | 19 + .../ShellPkg/Include/Library/AcpiViewCommandLib.h | 46 + .../ShellPkg/Include/Library/BcfgCommandLib.h | 46 + .../ShellPkg/Include/Library/HandleParsingLib.h | 404 ++ .../ShellPkg/Include/Library/ShellCEntryLib.h | 34 + .../ShellPkg/Include/Library/ShellCommandLib.h | 798 +++ .../Firmware/ShellPkg/Include/Library/ShellLib.h | 1432 +++++ .../Include/Protocol/EfiShellEnvironment2.h | 969 ++++ .../ShellPkg/Include/Protocol/EfiShellInterface.h | 88 + .../UefiHandleParsingLib/UefiHandleParsingLib.c | 3732 +++++++++++++ .../UefiHandleParsingLib/UefiHandleParsingLib.h | 294 + .../UefiHandleParsingLib/UefiHandleParsingLib.inf | 336 ++ .../UefiHandleParsingLib/UefiHandleParsingLib.uni | 508 ++ .../UefiShellAcpiViewCommandLib/AcpiParser.c | 740 +++ .../UefiShellAcpiViewCommandLib/AcpiParser.h | 899 +++ .../UefiShellAcpiViewCommandLib/AcpiTableParser.c | 251 + .../UefiShellAcpiViewCommandLib/AcpiTableParser.h | 127 + .../Library/UefiShellAcpiViewCommandLib/AcpiView.c | 324 ++ .../Library/UefiShellAcpiViewCommandLib/AcpiView.h | 94 + .../UefiShellAcpiViewCommandLib/AcpiViewConfig.c | 246 + .../UefiShellAcpiViewCommandLib/AcpiViewConfig.h | 177 + .../Arm/SbbrValidator.c | 222 + .../Arm/SbbrValidator.h | 91 + .../Parsers/Aest/AestParser.c | 755 +++ .../Parsers/Bgrt/BgrtParser.c | 65 + .../Parsers/Dbg2/Dbg2Parser.c | 302 + .../Parsers/Dsdt/DsdtParser.c | 42 + .../Parsers/Facs/FacsParser.c | 71 + .../Parsers/Fadt/FadtParser.c | 319 ++ .../Parsers/Gtdt/GtdtParser.c | 364 ++ .../Parsers/Hmat/HmatParser.c | 650 +++ .../Parsers/Iort/IortParser.c | 764 +++ .../Parsers/Madt/MadtParser.c | 374 ++ .../Parsers/Madt/MadtParser.h | 40 + .../Parsers/Mcfg/McfgParser.c | 90 + .../Parsers/Pcct/PcctParser.c | 615 +++ .../Parsers/Pcct/PcctParser.h | 33 + .../Parsers/Pptt/PpttParser.c | 478 ++ .../Parsers/Pptt/PpttParser.h | 38 + .../Parsers/Rsdp/RsdpParser.c | 164 + .../Parsers/Slit/SlitParser.c | 188 + .../Parsers/Spcr/SpcrParser.c | 144 + .../Parsers/Srat/SratParser.c | 542 ++ .../Parsers/Ssdt/SsdtParser.c | 42 + .../Parsers/Xsdt/XsdtParser.c | 140 + .../UefiShellAcpiViewCommandLib.c | 447 ++ .../UefiShellAcpiViewCommandLib.inf | 85 + .../UefiShellAcpiViewCommandLib.uni | 139 + .../UefiShellBcfgCommandLib.c | 1900 +++++++ .../UefiShellBcfgCommandLib.inf | 42 + .../UefiShellBcfgCommandLib.uni | 153 + .../UefiShellCEntryLib/UefiShellCEntryLib.c | 93 + .../UefiShellCEntryLib/UefiShellCEntryLib.inf | 39 + .../Library/UefiShellCommandLib/ConsistMapping.c | 1692 ++++++ .../UefiShellCommandLib/UefiShellCommandLib.c | 2228 ++++++++ .../UefiShellCommandLib/UefiShellCommandLib.h | 84 + .../UefiShellCommandLib/UefiShellCommandLib.inf | 65 + .../Library/UefiShellDebug1CommandsLib/Comp.c | 493 ++ .../Library/UefiShellDebug1CommandsLib/Compress.c | 1382 +++++ .../Library/UefiShellDebug1CommandsLib/Compress.h | 33 + .../Library/UefiShellDebug1CommandsLib/Dblk.c | 201 + .../Library/UefiShellDebug1CommandsLib/Dmem.c | 222 + .../Library/UefiShellDebug1CommandsLib/DmpStore.c | 859 +++ .../Library/UefiShellDebug1CommandsLib/Edit/Edit.c | 156 + .../UefiShellDebug1CommandsLib/Edit/FileBuffer.c | 3321 +++++++++++ .../UefiShellDebug1CommandsLib/Edit/FileBuffer.h | 240 + .../Edit/MainTextEditor.c | 1974 +++++++ .../Edit/MainTextEditor.h | 66 + .../Library/UefiShellDebug1CommandsLib/Edit/Misc.c | 84 + .../Library/UefiShellDebug1CommandsLib/Edit/Misc.h | 44 + .../Edit/TextEditStrings.uni | 69 + .../UefiShellDebug1CommandsLib/Edit/TextEditor.h | 26 + .../Edit/TextEditorTypes.h | 97 + .../UefiShellDebug1CommandsLib/EditInputBar.c | 324 ++ .../UefiShellDebug1CommandsLib/EditInputBar.h | 81 + .../UefiShellDebug1CommandsLib/EditMenuBar.c | 210 + .../UefiShellDebug1CommandsLib/EditMenuBar.h | 113 + .../UefiShellDebug1CommandsLib/EditStatusBar.c | 224 + .../UefiShellDebug1CommandsLib/EditStatusBar.h | 96 + .../UefiShellDebug1CommandsLib/EditTitleBar.c | 201 + .../UefiShellDebug1CommandsLib/EditTitleBar.h | 68 + .../UefiShellDebug1CommandsLib/EfiCompress.c | 158 + .../UefiShellDebug1CommandsLib/EfiDecompress.c | 180 + .../HexEdit/BufferImage.c | 2469 +++++++++ .../HexEdit/BufferImage.h | 267 + .../UefiShellDebug1CommandsLib/HexEdit/Clipboard.c | 106 + .../UefiShellDebug1CommandsLib/HexEdit/Clipboard.h | 63 + .../UefiShellDebug1CommandsLib/HexEdit/DiskImage.c | 411 ++ .../UefiShellDebug1CommandsLib/HexEdit/DiskImage.h | 89 + .../UefiShellDebug1CommandsLib/HexEdit/FileImage.c | 392 ++ .../UefiShellDebug1CommandsLib/HexEdit/FileImage.h | 77 + .../UefiShellDebug1CommandsLib/HexEdit/HexEdit.c | 271 + .../UefiShellDebug1CommandsLib/HexEdit/HexEditor.h | 35 + .../HexEdit/HexEditorTypes.h | 120 + .../HexEdit/HexeditStrings.uni | 70 + .../HexEdit/MainHexEditor.c | 2372 ++++++++ .../HexEdit/MainHexEditor.h | 69 + .../UefiShellDebug1CommandsLib/HexEdit/MemImage.c | 278 + .../UefiShellDebug1CommandsLib/HexEdit/MemImage.h | 86 + .../UefiShellDebug1CommandsLib/HexEdit/Misc.c | 256 + .../UefiShellDebug1CommandsLib/HexEdit/Misc.h | 87 + .../UefiShellDebug1CommandsLib/LoadPciRom.c | 412 ++ .../Library/UefiShellDebug1CommandsLib/MemMap.c | 404 ++ .../Library/UefiShellDebug1CommandsLib/Mm.c | 631 +++ .../Library/UefiShellDebug1CommandsLib/Mode.c | 122 + .../Library/UefiShellDebug1CommandsLib/Pci.c | 5815 ++++++++++++++++++++ .../Library/UefiShellDebug1CommandsLib/Pci.h | 58 + .../Library/UefiShellDebug1CommandsLib/SerMode.c | 365 ++ .../Library/UefiShellDebug1CommandsLib/SetSize.c | 104 + .../Library/UefiShellDebug1CommandsLib/SetVar.c | 469 ++ .../SmbiosView/EventLogInfo.c | 409 ++ .../SmbiosView/EventLogInfo.h | 106 + .../SmbiosView/LibSmbiosView.c | 367 ++ .../SmbiosView/LibSmbiosView.h | 153 + .../SmbiosView/PrintInfo.c | 3456 ++++++++++++ .../SmbiosView/PrintInfo.h | 441 ++ .../SmbiosView/QueryTable.c | 4836 ++++++++++++++++ .../SmbiosView/QueryTable.h | 814 +++ .../SmbiosView/SmbiosView.c | 999 ++++ .../SmbiosView/SmbiosView.h | 123 + .../SmbiosView/SmbiosViewStrings.uni | 502 ++ .../UefiShellDebug1CommandsLib.c | 421 ++ .../UefiShellDebug1CommandsLib.h | 377 ++ .../UefiShellDebug1CommandsLib.inf | 132 + .../UefiShellDebug1CommandsLib.uni | 1173 ++++ .../Library/UefiShellDriver1CommandsLib/Connect.c | 543 ++ .../Library/UefiShellDriver1CommandsLib/DevTree.c | 271 + .../Library/UefiShellDriver1CommandsLib/Devices.c | 263 + .../Library/UefiShellDriver1CommandsLib/Dh.c | 1191 ++++ .../UefiShellDriver1CommandsLib/Disconnect.c | 198 + .../Library/UefiShellDriver1CommandsLib/Drivers.c | 423 ++ .../Library/UefiShellDriver1CommandsLib/DrvCfg.c | 1406 +++++ .../Library/UefiShellDriver1CommandsLib/DrvDiag.c | 457 ++ .../Library/UefiShellDriver1CommandsLib/OpenInfo.c | 210 + .../UefiShellDriver1CommandsLib/Reconnect.c | 93 + .../UefiShellDriver1CommandsLib.c | 98 + .../UefiShellDriver1CommandsLib.h | 222 + .../UefiShellDriver1CommandsLib.inf | 68 + .../UefiShellDriver1CommandsLib.uni | 753 +++ .../Library/UefiShellDriver1CommandsLib/Unload.c | 142 + .../UefiShellInstall1CommandsLib.c | 53 + .../UefiShellInstall1CommandsLib.inf | 46 + .../Library/UefiShellLevel1CommandsLib/Exit.c | 91 + .../Library/UefiShellLevel1CommandsLib/For.c | 745 +++ .../Library/UefiShellLevel1CommandsLib/Goto.c | 99 + .../Library/UefiShellLevel1CommandsLib/If.c | 1105 ++++ .../Library/UefiShellLevel1CommandsLib/Shift.c | 58 + .../Library/UefiShellLevel1CommandsLib/Stall.c | 78 + .../UefiShellLevel1CommandsLib.c | 302 + .../UefiShellLevel1CommandsLib.h | 203 + .../UefiShellLevel1CommandsLib.inf | 53 + .../UefiShellLevel1CommandsLib.uni | 498 ++ .../Library/UefiShellLevel2CommandsLib/Attrib.c | 271 + .../Library/UefiShellLevel2CommandsLib/Cd.c | 345 ++ .../Library/UefiShellLevel2CommandsLib/Cp.c | 776 +++ .../Library/UefiShellLevel2CommandsLib/Load.c | 282 + .../Library/UefiShellLevel2CommandsLib/Ls.c | 905 +++ .../Library/UefiShellLevel2CommandsLib/Map.c | 1296 +++++ .../Library/UefiShellLevel2CommandsLib/MkDir.c | 161 + .../Library/UefiShellLevel2CommandsLib/Mv.c | 860 +++ .../Library/UefiShellLevel2CommandsLib/Parse.c | 311 ++ .../Library/UefiShellLevel2CommandsLib/Reset.c | 164 + .../Library/UefiShellLevel2CommandsLib/Rm.c | 374 ++ .../Library/UefiShellLevel2CommandsLib/Set.c | 168 + .../Library/UefiShellLevel2CommandsLib/TimeDate.c | 966 ++++ .../UefiShellLevel2CommandsLib.c | 344 ++ .../UefiShellLevel2CommandsLib.h | 363 ++ .../UefiShellLevel2CommandsLib.inf | 79 + .../UefiShellLevel2CommandsLib.uni | 1079 ++++ .../Library/UefiShellLevel2CommandsLib/Vol.c | 307 ++ .../Library/UefiShellLevel3CommandsLib/Alias.c | 280 + .../Library/UefiShellLevel3CommandsLib/Cls.c | 224 + .../Library/UefiShellLevel3CommandsLib/Echo.c | 115 + .../Library/UefiShellLevel3CommandsLib/GetMtc.c | 91 + .../Library/UefiShellLevel3CommandsLib/Help.c | 468 ++ .../Library/UefiShellLevel3CommandsLib/Pause.c | 101 + .../Library/UefiShellLevel3CommandsLib/Touch.c | 286 + .../Library/UefiShellLevel3CommandsLib/Type.c | 323 ++ .../UefiShellLevel3CommandsLib.c | 95 + .../UefiShellLevel3CommandsLib.h | 155 + .../UefiShellLevel3CommandsLib.inf | 70 + .../UefiShellLevel3CommandsLib.uni | 539 ++ .../Library/UefiShellLevel3CommandsLib/Ver.c | 158 + .../ShellPkg/Library/UefiShellLib/UefiShellLib.c | 4392 +++++++++++++++ .../ShellPkg/Library/UefiShellLib/UefiShellLib.h | 90 + .../ShellPkg/Library/UefiShellLib/UefiShellLib.inf | 65 + .../UefiShellNetwork1CommandsLib/Ifconfig.c | 1441 +++++ .../Library/UefiShellNetwork1CommandsLib/Ping.c | 1708 ++++++ .../UefiShellNetwork1CommandsLib.c | 84 + .../UefiShellNetwork1CommandsLib.h | 70 + .../UefiShellNetwork1CommandsLib.inf | 64 + .../UefiShellNetwork1CommandsLib.uni | 176 + .../UefiShellNetwork2CommandsLib/Ifconfig6.c | 1906 +++++++ .../Library/UefiShellNetwork2CommandsLib/Ping6.c | 1367 +++++ .../UefiShellNetwork2CommandsLib.c | 86 + .../UefiShellNetwork2CommandsLib.h | 67 + .../UefiShellNetwork2CommandsLib.inf | 60 + .../UefiShellNetwork2CommandsLib.uni | 160 + .../Devices/EFI/Firmware/ShellPkg/ShellPkg.ci.yaml | 70 + .../Devices/EFI/Firmware/ShellPkg/ShellPkg.dec | 138 + .../Devices/EFI/Firmware/ShellPkg/ShellPkg.dsc | 158 + 263 files changed, 124106 insertions(+) create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/AcpiViewApp/AcpiViewApp.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/AcpiViewApp/AcpiViewApp.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/AcpiViewApp/AcpiViewApp.uni create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ConsoleLogger.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ConsoleLogger.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ConsoleWrappers.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ConsoleWrappers.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/FileHandleInternal.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/FileHandleWrappers.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/FileHandleWrappers.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/Shell.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/Shell.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/Shell.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/Shell.uni create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellEnvVar.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellEnvVar.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellManParser.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellManParser.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellParametersProtocol.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellParametersProtocol.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellProtocol.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellProtocol.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellCTestApp/README.txt create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellCTestApp/ShellCTestApp.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellCTestApp/ShellCTestApp.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellCTestApp/TestArgv.log create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellCTestApp/TestArgv.nsh create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellExecTestApp/SA.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellExecTestApp/SA.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellSortTestApp/ShellSortTestApp.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellSortTestApp/ShellSortTestApp.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.uni create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpApp.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpApp.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicCommand.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicCommand.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpInternal.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpTrace.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpUtilities.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Literals.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Literals.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.uni create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.uni create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpApp.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpApp.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpDynamicCommand.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpDynamicCommand.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Guid/ShellAliasGuid.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Guid/ShellEnvironment2Ext.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Guid/ShellLibHiiGuid.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Guid/ShellMapGuid.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Guid/ShellPkgTokenSpace.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Guid/ShellVariableGuid.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Library/AcpiViewCommandLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Library/BcfgCommandLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Library/HandleParsingLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Library/ShellCEntryLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Library/ShellCommandLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Library/ShellLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Protocol/EfiShellEnvironment2.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Protocol/EfiShellInterface.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.uni create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiTableParser.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiTableParser.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiView.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiView.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiViewConfig.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiViewConfig.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Arm/SbbrValidator.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Arm/SbbrValidator.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Aest/AestParser.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Bgrt/BgrtParser.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Dbg2/Dbg2Parser.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Dsdt/DsdtParser.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Facs/FacsParser.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Fadt/FadtParser.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Gtdt/GtdtParser.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Hmat/HmatParser.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Iort/IortParser.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Madt/MadtParser.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Madt/MadtParser.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Mcfg/McfgParser.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Pcct/PcctParser.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Pcct/PcctParser.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Pptt/PpttParser.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Pptt/PpttParser.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Rsdp/RsdpParser.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Slit/SlitParser.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Spcr/SpcrParser.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Srat/SratParser.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Ssdt/SsdtParser.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Xsdt/XsdtParser.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.uni create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.uni create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellCommandLib/ConsistMapping.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Comp.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Compress.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Compress.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Dblk.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Dmem.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/DmpStore.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Edit.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditStrings.uni create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditor.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditorTypes.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditInputBar.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditInputBar.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditMenuBar.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditMenuBar.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditStatusBar.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditStatusBar.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditTitleBar.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditTitleBar.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EfiCompress.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EfiDecompress.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/BufferImage.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/BufferImage.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Clipboard.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Clipboard.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/DiskImage.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/DiskImage.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/FileImage.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/FileImage.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexEdit.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexEditor.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexEditorTypes.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexeditStrings.uni create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MainHexEditor.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MainHexEditor.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MemImage.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MemImage.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Misc.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Misc.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/LoadPciRom.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/MemMap.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Mm.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Mode.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Pci.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Pci.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SerMode.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SetSize.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SetVar.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/EventLogInfo.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/EventLogInfo.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/LibSmbiosView.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/LibSmbiosView.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/PrintInfo.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/PrintInfo.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/QueryTable.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/QueryTable.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/SmbiosView.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/SmbiosView.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/SmbiosViewStrings.uni create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.uni create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Connect.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/DevTree.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Devices.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Dh.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Disconnect.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Drivers.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/DrvCfg.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/DrvDiag.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/OpenInfo.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Reconnect.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.uni create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Unload.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/Exit.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/For.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/Goto.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/If.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/Shift.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/Stall.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.uni create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Attrib.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Cd.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Load.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Map.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/MkDir.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Parse.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Reset.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Rm.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Set.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/TimeDate.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.uni create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Vol.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Alias.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Cls.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Echo.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/GetMtc.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Help.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Pause.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Touch.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Type.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.uni create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Ver.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLib/UefiShellLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLib/UefiShellLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLib/UefiShellLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ifconfig.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ping.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.uni create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork2CommandsLib/Ifconfig6.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork2CommandsLib/Ping6.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.uni create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/ShellPkg.ci.yaml create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/ShellPkg.dec create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/ShellPkg.dsc (limited to 'src/VBox/Devices/EFI/Firmware/ShellPkg') diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/AcpiViewApp/AcpiViewApp.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/AcpiViewApp/AcpiViewApp.c new file mode 100644 index 00000000..e4ade540 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/AcpiViewApp/AcpiViewApp.c @@ -0,0 +1,40 @@ +/** @file + Main file for AcpiViewApp application + + Copyright (c) 2020, ARM Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include + +#include + +// +// 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_GET_HELP_ACPIVIEW); + +/** + Application Entry Point wrapper around the shell command + + @param[in] ImageHandle Handle to the Image (NULL if internal). + @param[in] SystemTable Pointer to the System Table (NULL if internal). +**/ +EFI_STATUS +EFIAPI +AcpiViewAppMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return ShellCommandRunAcpiView (gImageHandle, SystemTable); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/AcpiViewApp/AcpiViewApp.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/AcpiViewApp/AcpiViewApp.inf new file mode 100644 index 00000000..ab5f752d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/AcpiViewApp/AcpiViewApp.inf @@ -0,0 +1,34 @@ +## @file +# EFI application that displays and verifies ACPI tables +# +# Copyright (c) 2020, ARM Limited. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x0001001B + BASE_NAME = AcpiViewApp + FILE_GUID = 46361B5B-AF17-41FF-95F9-E1BCE08435B9 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = AcpiViewAppMain + UEFI_HII_RESOURCE_SECTION = TRUE + +[Sources.common] + AcpiViewApp.c + AcpiViewApp.uni + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + UefiLib + BaseLib + UefiApplicationEntryPoint + AcpiViewCommandLib diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/AcpiViewApp/AcpiViewApp.uni b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/AcpiViewApp/AcpiViewApp.uni new file mode 100644 index 00000000..c56f2108 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/AcpiViewApp/AcpiViewApp.uni @@ -0,0 +1,122 @@ +// @file +// +// Standalone EFI application that displays and verifies ACPI tables +// +// Copyright (c) 2020, ARM Limited. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// + +/=# + +#langdef en-US "english" + +#string STR_GET_HELP_ACPIVIEW #language en-US "" +".TH acpiview 0 "Display ACPI information."\r\n" +".SH NAME\r\n" +"Display ACPI Table information.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"ACPIVIEWAPP.EFI [[-?] | [[[[-l] | [-s AcpiTable [-d]]] [-q] [-h]] [-r Spec]]]\r\n" +" \r\n" +".SH OPTIONS\r\n" +" \r\n" +" -l - Display list of installed ACPI Tables.\r\n" +" -s - Display only the specified AcpiTable type and only support single\r\n" +" invocation option.\r\n" +" AcpiTable : The required ACPI Table type.\r\n" +" -d - Generate a binary file dump of the specified AcpiTable.\r\n" +" -q - Quiet. Suppress errors and warnings. Disables consistency checks.\r\n" +" -h - Enable colour highlighting.\r\n" +" -r - Validate that all required ACPI tables are installed\r\n" +" Spec : Specification to validate against.\r\n" +" For Arm, the possible values are:\r\n" +" 0 - Server Base Boot Requirements v1.0\r\n" +" 1 - Server Base Boot Requirements v1.1\r\n" +" 2 - Server Base Boot Requirements v1.2\r\n" +" -? - Show help.\r\n" +" \r\n" +".SH DESCRIPTION\r\n" +" \r\n" +" This program is provided to allow examination of ACPI table values from the\r\n" +" UEFI Shell. This can help with investigations, especially at that stage\r\n" +" where the tables are not enabling an OS to boot.\r\n" +" The program is not exhaustive, and only encapsulates detailed knowledge of a\r\n" +" limited number of table types.\r\n" +" \r\n" +" Default behaviour is to display the content of all tables installed.\r\n" +" 'Known' table types (listed in NOTES below) will be parsed and displayed\r\n" +" with descriptions and field values. Where appropriate a degree of\r\n" +" consistency checking is done and errors may be reported in the output.\r\n" +" Other table types will be displayed as an array of Hexadecimal bytes.\r\n" +" \r\n" +" To facilitate debugging, the -s and -d options can be used to generate a\r\n" +" binary file image of a table that can be copied elsewhere for investigation\r\n" +" using tools such as those provided by acpica.org. This is especially\r\n" +" relevant for AML type tables like DSDT and SSDT.\r\n" +" \r\n" +"NOTES:\r\n" +" 1. The AcpiTable parameter can match any installed table type.\r\n" +" Tables without specific handling will be displayed as a raw hex dump (or\r\n" +" dumped to a file if -d is used).\r\n" +" 2. -s option supports to display the specified AcpiTable type that is present\r\n" +" in the system. For normal type AcpiTable, it would display the data of the\r\n" +" AcpiTable and AcpiTable header. The following type may contain header type\r\n" +" other than AcpiTable header. The actual header can refer to the ACPI spec\r\n" +" 6.3\r\n" +" Extra A. Particular types:\r\n" +" APIC - Multiple APIC Description Table (MADT)\r\n" +" BGRT - Boot Graphics Resource Table\r\n" +" DBG2 - Debug Port Table 2\r\n" +" DSDT - Differentiated System Description Table\r\n" +" FACP - Fixed ACPI Description Table (FADT)\r\n" +" GTDT - Generic Timer Description Table\r\n" +" IORT - IO Remapping Table\r\n" +" MCFG - Memory Mapped Config Space Base Address Description Table\r\n" +" PPTT - Processor Properties Topology Table\r\n" +" RSDP - Root System Description Pointer\r\n" +" SLIT - System Locality Information Table\r\n" +" SPCR - Serial Port Console Redirection Table\r\n" +" SRAT - System Resource Affinity Table\r\n" +" SSDT - Secondary SystemDescription Table\r\n" +" XSDT - Extended System Description Table\r\n" +" \r\n" +".SH STANDARDS\r\n" +" \r\n" +" Table details correspond to those in 'Advanced Configuration and Power\r\n" +" Interface Specification' Version 6.3 [January 2019]\r\n" +" (https://uefi.org/specifications)\r\n" +" \r\n" +" NOTE: The nature of the ACPI standard means that almost all tables in 6.3\r\n" +" will be 'backwards compatible' with prior version of the specification\r\n" +" in terms of structure, so formatted output should be correct. The main\r\n" +" exception will be that previously 'reserved' fields will be reported\r\n" +" with new names, where they have been added in later versions of the\r\n" +" specification.\r\n" +" \r\n" +".SH EXAMPLES\r\n" +" \r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display a list of the installed table types:\r\n" +" fs0:\> acpiviewapp.efi -l\r\n" +" \r\n" +" * To parse and display a specific table type:\r\n" +" fs0:\> acpiviewapp.efi -s GTDT\r\n" +" \r\n" +" * To save a binary dump of the contents of a table to a file\r\n" +" in the current working directory:\r\n" +" fs0:\> acpiviewapp.efi -s DSDT -d\r\n" +" \r\n" +" * To display contents of all ACPI tables:\r\n" +" fs0:\> acpiviewapp.efi\r\n" +" \r\n" +" * To check if all Server Base Boot Requirements (SBBR) v1.2 mandatory\r\n" +" ACPI tables are installed (Arm only):\r\n" +" fs0:\> acpiviewapp.efi -r 2\r\n" +" \r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS Data was displayed as requested.\r\n" +" SHELL_INVALID_PARAMETER ACPI Table parsing failed.\r\n" +" \r\n" diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ConsoleLogger.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ConsoleLogger.c new file mode 100644 index 00000000..2fe63dd4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ConsoleLogger.c @@ -0,0 +1,1237 @@ +/** @file + Provides interface to shell console logger. + + (C) Copyright 2013 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2016 Hewlett-Packard Development Company, L.P.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "Shell.h" + +/** + Install our intermediate ConOut into the system table to + keep a log of all the info that is displayed to the user. + + @param[in] ScreensToSave Sets how many screen-worths of data to save. + @param[out] ConsoleInfo The object to pass into later functions. + + @retval EFI_SUCCESS The operation was successful. + @return other The operation failed. + + @sa ConsoleLoggerResetBuffers + @sa InstallProtocolInterface +**/ +EFI_STATUS +ConsoleLoggerInstall( + IN CONST UINTN ScreensToSave, + OUT CONSOLE_LOGGER_PRIVATE_DATA **ConsoleInfo + ) +{ + EFI_STATUS Status; + ASSERT(ConsoleInfo != NULL); + + (*ConsoleInfo) = AllocateZeroPool(sizeof(CONSOLE_LOGGER_PRIVATE_DATA)); + if ((*ConsoleInfo) == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + (*ConsoleInfo)->Signature = CONSOLE_LOGGER_PRIVATE_DATA_SIGNATURE; + (*ConsoleInfo)->OldConOut = gST->ConOut; + (*ConsoleInfo)->OldConHandle = gST->ConsoleOutHandle; + (*ConsoleInfo)->Buffer = NULL; + (*ConsoleInfo)->BufferSize = 0; + (*ConsoleInfo)->OriginalStartRow = 0; + (*ConsoleInfo)->CurrentStartRow = 0; + (*ConsoleInfo)->RowsPerScreen = 0; + (*ConsoleInfo)->ColsPerScreen = 0; + (*ConsoleInfo)->Attributes = NULL; + (*ConsoleInfo)->AttribSize = 0; + (*ConsoleInfo)->ScreenCount = ScreensToSave; + (*ConsoleInfo)->HistoryMode.MaxMode = 1; + (*ConsoleInfo)->HistoryMode.Mode = 0; + (*ConsoleInfo)->HistoryMode.Attribute = 0; + (*ConsoleInfo)->HistoryMode.CursorColumn = 0; + (*ConsoleInfo)->HistoryMode.CursorRow = 0; + (*ConsoleInfo)->HistoryMode.CursorVisible = FALSE; + (*ConsoleInfo)->OurConOut.Reset = ConsoleLoggerReset; + (*ConsoleInfo)->OurConOut.OutputString = ConsoleLoggerOutputString; + (*ConsoleInfo)->OurConOut.TestString = ConsoleLoggerTestString; + (*ConsoleInfo)->OurConOut.QueryMode = ConsoleLoggerQueryMode; + (*ConsoleInfo)->OurConOut.SetMode = ConsoleLoggerSetMode; + (*ConsoleInfo)->OurConOut.SetAttribute = ConsoleLoggerSetAttribute; + (*ConsoleInfo)->OurConOut.ClearScreen = ConsoleLoggerClearScreen; + (*ConsoleInfo)->OurConOut.SetCursorPosition = ConsoleLoggerSetCursorPosition; + (*ConsoleInfo)->OurConOut.EnableCursor = ConsoleLoggerEnableCursor; + (*ConsoleInfo)->OurConOut.Mode = gST->ConOut->Mode; + (*ConsoleInfo)->Enabled = TRUE; + + Status = ConsoleLoggerResetBuffers(*ConsoleInfo); + if (EFI_ERROR(Status)) { + SHELL_FREE_NON_NULL((*ConsoleInfo)); + *ConsoleInfo = NULL; + return (Status); + } + + Status = gBS->InstallProtocolInterface(&gImageHandle, &gEfiSimpleTextOutProtocolGuid, EFI_NATIVE_INTERFACE, (VOID*)&((*ConsoleInfo)->OurConOut)); + if (EFI_ERROR(Status)) { + SHELL_FREE_NON_NULL((*ConsoleInfo)->Buffer); + SHELL_FREE_NON_NULL((*ConsoleInfo)->Attributes); + SHELL_FREE_NON_NULL((*ConsoleInfo)); + *ConsoleInfo = NULL; + return (Status); + } + + gST->ConsoleOutHandle = gImageHandle; + gST->ConOut = &(*ConsoleInfo)->OurConOut; + + // + // Update the CRC32 in the EFI System Table header + // + gST->Hdr.CRC32 = 0; + gBS->CalculateCrc32 ( + (UINT8 *)&gST->Hdr, + gST->Hdr.HeaderSize, + &gST->Hdr.CRC32 + ); + return (Status); +} + +/** + Return the system to the state it was before InstallConsoleLogger + was installed. + + @param[in] ConsoleInfo The object from the install function. + + @retval EFI_SUCCESS The operation was successful + @return other The operation failed. This was from UninstallProtocolInterface. +**/ +EFI_STATUS +ConsoleLoggerUninstall( + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ) +{ + ASSERT(ConsoleInfo != NULL); + ASSERT(ConsoleInfo->OldConOut != NULL); + + if (ConsoleInfo->Buffer != NULL) { + FreePool(ConsoleInfo->Buffer); + DEBUG_CODE(ConsoleInfo->Buffer = NULL;); + DEBUG_CODE(ConsoleInfo->BufferSize = 0;); + } + if (ConsoleInfo->Attributes != NULL) { + FreePool(ConsoleInfo->Attributes); + DEBUG_CODE(ConsoleInfo->Attributes = NULL;); + DEBUG_CODE(ConsoleInfo->AttribSize = 0;); + } + + gST->ConsoleOutHandle = ConsoleInfo->OldConHandle; + gST->ConOut = ConsoleInfo->OldConOut; + + // + // Update the CRC32 in the EFI System Table header + // + gST->Hdr.CRC32 = 0; + gBS->CalculateCrc32 ( + (UINT8 *)&gST->Hdr, + gST->Hdr.HeaderSize, + &gST->Hdr.CRC32 + ); + + return (gBS->UninstallProtocolInterface(gImageHandle, &gEfiSimpleTextOutProtocolGuid, (VOID*)&ConsoleInfo->OurConOut)); +} + +/** + Displays previously logged output back to the screen. + + This will scroll the screen forwards and backwards through the log of previous + output. If Rows is 0 then the size of 1/2 the screen will be scrolled. If Rows + is (UINTN)(-1) then the size of the screen will be scrolled. + + @param[in] Forward If TRUE then the log will be displayed forwards (scroll to newer). + If FALSE then the log will be displayed backwards (scroll to older). + @param[in] Rows Determines how many rows the log should scroll. + @param[in] ConsoleInfo The pointer to the instance of the console logger information. +**/ +EFI_STATUS +ConsoleLoggerDisplayHistory( + IN CONST BOOLEAN Forward, + IN CONST UINTN Rows, + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ) +{ + UINTN RowChange; + + ASSERT(ConsoleInfo != NULL); + + // + // Calculate the row number change + // + switch (Rows) { + case ((UINTN)(-1)): + RowChange = ConsoleInfo->RowsPerScreen; + break; + case (0): + RowChange = ConsoleInfo->RowsPerScreen / 2; + break; + default: + RowChange = Rows; + break; + } + + // + // Do the math for direction + // + if (Forward) { + if ((ConsoleInfo->OriginalStartRow - ConsoleInfo->CurrentStartRow) < RowChange) { + RowChange = ConsoleInfo->OriginalStartRow - ConsoleInfo->CurrentStartRow; + } + } else { + if (ConsoleInfo->CurrentStartRow < RowChange) { + RowChange = ConsoleInfo->CurrentStartRow; + } + } + + // + // If we are already at one end or the other + // + if (RowChange == 0) { + return (EFI_SUCCESS); + } + + // + // Clear the screen + // + ConsoleInfo->OldConOut->ClearScreen(ConsoleInfo->OldConOut); + + // + // Set the new start row + // + if (Forward) { + ConsoleInfo->CurrentStartRow += RowChange; + } else { + ConsoleInfo->CurrentStartRow -= RowChange; + } + + // + // Change the screen + // + return (UpdateDisplayFromHistory(ConsoleInfo)); +} + +/** + Function to return to normal output whent he scrolling is complete. + @param[in] ConsoleInfo The pointer to the instance of the console logger information. + + @retval EFI_SUCCESS The operation was successful. + @return other The operation failed. See UpdateDisplayFromHistory. + + @sa UpdateDisplayFromHistory +**/ +EFI_STATUS +ConsoleLoggerStopHistory( + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ) +{ + ASSERT(ConsoleInfo != NULL); + if (ConsoleInfo->CurrentStartRow == ConsoleInfo->OriginalStartRow) { + return (EFI_SUCCESS); + } + + // + // Clear the screen + // + ConsoleInfo->OldConOut->ClearScreen(ConsoleInfo->OldConOut); + + ConsoleInfo->CurrentStartRow = ConsoleInfo->OriginalStartRow; + return (UpdateDisplayFromHistory(ConsoleInfo)); +} + +/** + Updates the hidden ConOut to be displaying the correct stuff. + @param[in] ConsoleInfo The pointer to the instance of the console logger information. + + @retval EFI_SUCCESS The operation was successful. + @return other The operation failed. +**/ +EFI_STATUS +UpdateDisplayFromHistory( + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ) +{ + EFI_STATUS Status; + EFI_STATUS RetVal; + CHAR16 *Screen; + INT32 *Attributes; + UINTN CurrentRow; + CHAR16 TempCharHolder; + UINTN Column; + INT32 CurrentAttrib; + UINTN CurrentColumn; + CHAR16 *StringSegment; + CHAR16 *StringSegmentEnd; + CHAR16 StringSegmentEndChar; + INT32 OrigAttribute; + + ASSERT(ConsoleInfo != NULL); + TempCharHolder = CHAR_NULL; + RetVal = EFI_SUCCESS; + OrigAttribute = ConsoleInfo->OldConOut->Mode->Attribute; + + // + // Disable cursor visibility and move it to the top left corner + // + ConsoleInfo->OldConOut->EnableCursor (ConsoleInfo->OldConOut, FALSE); + ConsoleInfo->OldConOut->SetCursorPosition (ConsoleInfo->OldConOut, 0, 0); + + Screen = &ConsoleInfo->Buffer[(ConsoleInfo->ColsPerScreen + 2) * ConsoleInfo->CurrentStartRow]; + Attributes = &ConsoleInfo->Attributes[ConsoleInfo->ColsPerScreen * ConsoleInfo->CurrentStartRow]; + for ( CurrentRow = 0 + ; CurrentRow < ConsoleInfo->RowsPerScreen + ; CurrentRow++ + , Screen += (ConsoleInfo->ColsPerScreen + 2) + , Attributes += ConsoleInfo->ColsPerScreen + ){ + // + // dont use the last char - prevents screen scroll + // + if (CurrentRow == (ConsoleInfo->RowsPerScreen-1)){ + TempCharHolder = Screen[ConsoleInfo->ColsPerScreen - 1]; + Screen[ConsoleInfo->ColsPerScreen - 1] = CHAR_NULL; + } + + for ( Column = 0 + ; Column < ConsoleInfo->ColsPerScreen + ; Column++ + ){ + if (Screen[Column] != CHAR_NULL) { + CurrentAttrib = Attributes[Column]; + CurrentColumn = Column; + StringSegment = &Screen[Column]; + + // + // Find the first char with a different attribute and make that temporarily NULL + // so we can do fewer printout statements. (later) restore that one and we will + // start at that column on the next loop. + // + StringSegmentEndChar = CHAR_NULL; + for ( StringSegmentEnd = StringSegment + ; *StringSegmentEnd != CHAR_NULL + ; StringSegmentEnd++ + , Column++ + ){ + if (Attributes[Column] != CurrentAttrib) { + StringSegmentEndChar = *StringSegmentEnd; + *StringSegmentEnd = CHAR_NULL; + break; + } + } // StringSegmentEnd loop + + // + // Now write out as much as had the same Attributes + // + + ConsoleInfo->OldConOut->SetAttribute(ConsoleInfo->OldConOut, CurrentAttrib); + ConsoleInfo->OldConOut->SetCursorPosition(ConsoleInfo->OldConOut, CurrentColumn, CurrentRow); + Status = ConsoleInfo->OldConOut->OutputString(ConsoleInfo->OldConOut, StringSegment); + + if (EFI_ERROR(Status)) { + ASSERT(FALSE); + RetVal = Status; + } + + // + // If we found a change in attribute put the character back and decrement the column + // so when it increments it will point at that character and we will start printing + // a segment with that new attribute + // + if (StringSegmentEndChar != CHAR_NULL) { + *StringSegmentEnd = StringSegmentEndChar; + StringSegmentEndChar = CHAR_NULL; + Column--; + } + } + } // column for loop + + // + // If we removed the last char and this was the last row put it back + // + if (TempCharHolder != CHAR_NULL) { + Screen[ConsoleInfo->ColsPerScreen - 1] = TempCharHolder; + TempCharHolder = CHAR_NULL; + } + } // row for loop + + // + // If we are setting the screen back to original turn on the cursor and make it visible + // and set the attributes back to what they were + // + if (ConsoleInfo->CurrentStartRow == ConsoleInfo->OriginalStartRow) { + ConsoleInfo->OldConOut->SetAttribute ( + ConsoleInfo->OldConOut, + ConsoleInfo->HistoryMode.Attribute + ); + ConsoleInfo->OldConOut->SetCursorPosition ( + ConsoleInfo->OldConOut, + ConsoleInfo->HistoryMode.CursorColumn, + ConsoleInfo->HistoryMode.CursorRow - ConsoleInfo->OriginalStartRow + ); + + Status = ConsoleInfo->OldConOut->EnableCursor ( + ConsoleInfo->OldConOut, + ConsoleInfo->HistoryMode.CursorVisible + ); + if (EFI_ERROR (Status)) { + RetVal = Status; + } + } else { + ConsoleInfo->OldConOut->SetAttribute ( + ConsoleInfo->OldConOut, + OrigAttribute + ); + } + + return (RetVal); +} + +/** + Reset the text output device hardware and optionally run diagnostics + + @param This pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL + @param ExtendedVerification Indicates that a more extensive test may be performed + + @retval EFI_SUCCESS The text output device was reset. + @retval EFI_DEVICE_ERROR The text output device is not functioning correctly and + could not be reset. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerReset ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + EFI_STATUS Status; + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This); + + // + // Forward the request to the original ConOut + // + Status = ConsoleInfo->OldConOut->Reset (ConsoleInfo->OldConOut, ExtendedVerification); + + // + // Check that the buffers are still correct for logging + // + if (!EFI_ERROR (Status)) { + ConsoleLoggerResetBuffers(ConsoleInfo); + if (ExtendedVerification) { + ConsoleInfo->OriginalStartRow = 0; + ConsoleInfo->CurrentStartRow = 0; + } + } + + return Status; +} + +/** + Appends a string to the history buffer. If the buffer is full then the oldest + information in the buffer will be dropped. Information is added in a line by + line manner such that an empty line takes up just as much space as a full line. + + @param[in] String String pointer to add. + @param[in] ConsoleInfo The pointer to the instance of the console logger information. +**/ +EFI_STATUS +AppendStringToHistory( + IN CONST CHAR16 *String, + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ) +{ + CONST CHAR16 *Walker; + UINTN CopySize; + UINTN PrintIndex; + UINTN Index; + + ASSERT(ConsoleInfo != NULL); + + for ( Walker = String + ; Walker != NULL && *Walker != CHAR_NULL + ; Walker++ + ){ + switch (*Walker) { + case (CHAR_BACKSPACE): + if (ConsoleInfo->HistoryMode.CursorColumn > 0) { + ConsoleInfo->HistoryMode.CursorColumn--; + } + break; + case (CHAR_LINEFEED): + if (ConsoleInfo->HistoryMode.CursorRow >= (INT32)((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount)-1)) { + // + // Should never be bigger + // + ASSERT(ConsoleInfo->HistoryMode.CursorRow == (INT32)((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount)-1)); + + // + // scroll history attributes 'up' 1 row and set the last row to default attribute + // + CopySize = ConsoleInfo->ColsPerScreen + * ((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount) - 1) + * sizeof(ConsoleInfo->Attributes[0]); + ASSERT(CopySize < ConsoleInfo->AttribSize); + CopyMem( + ConsoleInfo->Attributes, + ConsoleInfo->Attributes + ConsoleInfo->ColsPerScreen, + CopySize + ); + + for ( Index = 0 + ; Index < ConsoleInfo->ColsPerScreen + ; Index++ + ){ + *(ConsoleInfo->Attributes + (CopySize/sizeof(ConsoleInfo->Attributes[0])) + Index) = ConsoleInfo->HistoryMode.Attribute; + } + + // + // scroll history buffer 'up' 1 row and set the last row to spaces (L' ') + // + CopySize = (ConsoleInfo->ColsPerScreen + 2) + * ((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount) - 1) + * sizeof(ConsoleInfo->Buffer[0]); + ASSERT(CopySize < ConsoleInfo->BufferSize); + CopyMem( + ConsoleInfo->Buffer, + ConsoleInfo->Buffer + (ConsoleInfo->ColsPerScreen + 2), + CopySize + ); + + // + // Set that last row of chars to spaces + // + SetMem16(((UINT8*)ConsoleInfo->Buffer)+CopySize, ConsoleInfo->ColsPerScreen*sizeof(CHAR16), L' '); + } else { + // + // we are not on the last row + // + + // + // We should not be scrolling history + // + ASSERT (ConsoleInfo->OriginalStartRow == ConsoleInfo->CurrentStartRow); + // + // are we at the end of a row? + // + if (ConsoleInfo->HistoryMode.CursorRow == (INT32) (ConsoleInfo->OriginalStartRow + ConsoleInfo->RowsPerScreen - 1)) { + ConsoleInfo->OriginalStartRow++; + ConsoleInfo->CurrentStartRow++; + } + ConsoleInfo->HistoryMode.CursorRow++; + } + break; + case (CHAR_CARRIAGE_RETURN): + // + // Move the cursor to the beginning of the current row. + // + ConsoleInfo->HistoryMode.CursorColumn = 0; + break; + default: + // + // Acrtually print characters into the history buffer + // + + PrintIndex = ConsoleInfo->HistoryMode.CursorRow * ConsoleInfo->ColsPerScreen + ConsoleInfo->HistoryMode.CursorColumn; + + for ( // no initializer needed + ; ConsoleInfo->HistoryMode.CursorColumn < (INT32) ConsoleInfo->ColsPerScreen + ; ConsoleInfo->HistoryMode.CursorColumn++ + , PrintIndex++ + , Walker++ + ){ + if (*Walker == CHAR_NULL + ||*Walker == CHAR_BACKSPACE + ||*Walker == CHAR_LINEFEED + ||*Walker == CHAR_CARRIAGE_RETURN + ){ + Walker--; + break; + } + // + // The buffer is 2*CursorRow more since it has that many \r\n characters at the end of each row. + // + + ASSERT(PrintIndex + ConsoleInfo->HistoryMode.CursorRow < ConsoleInfo->BufferSize); + ConsoleInfo->Buffer[PrintIndex + (2*ConsoleInfo->HistoryMode.CursorRow)] = *Walker; + ASSERT(PrintIndex < ConsoleInfo->AttribSize); + ConsoleInfo->Attributes[PrintIndex] = ConsoleInfo->HistoryMode.Attribute; + } // for loop + + // + // Add the carriage return and line feed at the end of the lines + // + if (ConsoleInfo->HistoryMode.CursorColumn >= (INT32)ConsoleInfo->ColsPerScreen) { + AppendStringToHistory(L"\r\n", ConsoleInfo); + Walker--; + } + + break; + } // switch for character + } // for loop + + return (EFI_SUCCESS); +} + +/** + Worker function to handle printing the output to the screen + and the history buffer + + @param[in] String The string to output + @param[in] ConsoleInfo The pointer to the instance of the console logger information. + + @retval EFI_SUCCESS The string was printed + @retval EFI_DEVICE_ERROR The device reported an error while attempting to output + the text. + @retval EFI_UNSUPPORTED The output device's mode is not currently in a + defined text mode. + @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the + characters in the Unicode string could not be + rendered and were skipped. +**/ +EFI_STATUS +ConsoleLoggerOutputStringSplit( + IN CONST CHAR16 *String, + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ) +{ + EFI_STATUS Status; + + // + // Forward the request to the original ConOut + // + Status = ConsoleInfo->OldConOut->OutputString (ConsoleInfo->OldConOut, (CHAR16*)String); + + if (EFI_ERROR(Status)) { + return (Status); + } + + return (AppendStringToHistory(String, ConsoleInfo)); +} + +/** + Function to handle page break mode. + + This function will prompt for continue or break. + + @retval EFI_SUCCESS Continue was choosen + @return other Break was choosen +**/ +EFI_STATUS +ConsoleLoggerDoPageBreak( + VOID + ) +{ + SHELL_PROMPT_RESPONSE *Resp; + EFI_STATUS Status; + + Resp = NULL; + ASSERT(ShellInfoObject.PageBreakEnabled); + ShellInfoObject.PageBreakEnabled = FALSE; + Status = ShellPromptForResponseHii(ShellPromptResponseTypeQuitContinue, STRING_TOKEN(STR_SHELL_QUIT_CONT), ShellInfoObject.HiiHandle, (VOID**)&Resp); + ShellInfoObject.PageBreakEnabled = TRUE; + ASSERT(Resp != NULL); + if (Resp == NULL) { + return (EFI_NOT_FOUND); + } + if (EFI_ERROR(Status)) { + if (Resp != NULL) { + FreePool(Resp); + } + return (Status); + } + if (*Resp == ShellPromptResponseContinue) { + FreePool(Resp); + ShellInfoObject.ConsoleInfo->RowCounter = 0; +// ShellInfoObject.ConsoleInfo->OurConOut.Mode->CursorRow = 0; +// ShellInfoObject.ConsoleInfo->OurConOut.Mode->CursorColumn = 0; + + return (EFI_SUCCESS); + } else if (*Resp == ShellPromptResponseQuit) { + FreePool(Resp); + ShellInfoObject.ConsoleInfo->Enabled = FALSE; + // + // When user wants to quit, the shell should stop running the command. + // + gBS->SignalEvent (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak); + return (EFI_DEVICE_ERROR); + } else { + ASSERT(FALSE); + } + return (EFI_SUCCESS); +} +/** + Worker function to handle printing the output with page breaks. + + @param[in] String The string to output + @param[in] ConsoleInfo The pointer to the instance of the console logger information. + + @retval EFI_SUCCESS The string was printed + @retval EFI_DEVICE_ERROR The device reported an error while attempting to output + the text. + @retval EFI_UNSUPPORTED The output device's mode is not currently in a + defined text mode. + @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the + characters in the Unicode string could not be + rendered and were skipped. +**/ +EFI_STATUS +ConsoleLoggerPrintWithPageBreak( + IN CONST CHAR16 *String, + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ) +{ + CONST CHAR16 *Walker; + CONST CHAR16 *LineStart; + CHAR16 *StringCopy; + CHAR16 TempChar; + + StringCopy = NULL; + StringCopy = StrnCatGrow(&StringCopy, NULL, String, 0); + if (StringCopy == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + for ( Walker = StringCopy + , LineStart = StringCopy + ; Walker != NULL && *Walker != CHAR_NULL + ; Walker++ + ){ + switch (*Walker) { + case (CHAR_BACKSPACE): + if (ConsoleInfo->OurConOut.Mode->CursorColumn > 0) { + ConsoleInfo->OurConOut.Mode->CursorColumn--; + } + break; + case (CHAR_LINEFEED): + // + // add a temp NULL terminator + // + TempChar = *(Walker + 1); + *((CHAR16*)(Walker+1)) = CHAR_NULL; + + // + // output the string + // + ConsoleLoggerOutputStringSplit (LineStart, ConsoleInfo); + + // + // restore the temp NULL terminator to its original character + // + *((CHAR16*)(Walker+1)) = TempChar; + + // + // Update LineStart Variable + // + LineStart = Walker + 1; + + // + // increment row count + // + ShellInfoObject.ConsoleInfo->RowCounter++; + ConsoleInfo->OurConOut.Mode->CursorRow++; + + break; + case (CHAR_CARRIAGE_RETURN): + // + // Move the cursor to the beginning of the current row. + // + ConsoleInfo->OurConOut.Mode->CursorColumn = 0; + break; + default: + // + // increment column count + // + ConsoleInfo->OurConOut.Mode->CursorColumn++; + // + // check if that is the last column + // + if ((INTN)ConsoleInfo->ColsPerScreen == ConsoleInfo->OurConOut.Mode->CursorColumn + 1) { + // + // output a line similar to the linefeed character. + // + + // + // add a temp NULL terminator + // + TempChar = *(Walker + 1); + *((CHAR16*)(Walker+1)) = CHAR_NULL; + + // + // output the string + // + ConsoleLoggerOutputStringSplit (LineStart, ConsoleInfo); + + // + // restore the temp NULL terminator to its original character + // + *((CHAR16*)(Walker+1)) = TempChar; + + // + // Update LineStart Variable + // + LineStart = Walker + 1; + + // + // increment row count and zero the column + // + ShellInfoObject.ConsoleInfo->RowCounter++; + ConsoleInfo->OurConOut.Mode->CursorRow++; + ConsoleInfo->OurConOut.Mode->CursorColumn = 0; + } // last column on line + break; + } // switch for character + + // + // check if that was the last printable row. If yes handle PageBreak mode + // + if ((ConsoleInfo->RowsPerScreen) -1 == ShellInfoObject.ConsoleInfo->RowCounter) { + if (EFI_ERROR(ConsoleLoggerDoPageBreak())) { + // + // We got an error which means 'break' and halt the printing + // + SHELL_FREE_NON_NULL(StringCopy); + return (EFI_DEVICE_ERROR); + } + } + } // for loop + + if (LineStart != NULL && *LineStart != CHAR_NULL) { + ConsoleLoggerOutputStringSplit (LineStart, ConsoleInfo); + } + + SHELL_FREE_NON_NULL(StringCopy); + return (EFI_SUCCESS); +} + +/** + Write a Unicode string to the output device. + + @param[in] This Protocol instance pointer. + @param[in] WString The NULL-terminated Unicode string to be displayed on the output + device(s). All output devices must also support the Unicode + drawing defined in this file. + @retval EFI_SUCCESS The string was output to the device. + @retval EFI_DEVICE_ERROR The device reported an error while attempting to output + the text. + @retval EFI_UNSUPPORTED The output device's mode is not currently in a + defined text mode. + @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the + characters in the Unicode string could not be + rendered and were skipped. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerOutputString ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *WString + ) +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx; + EFI_KEY_DATA KeyData; + UINTN EventIndex; + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This); + if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) { + return (EFI_UNSUPPORTED); + } + ASSERT(ShellInfoObject.ConsoleInfo == ConsoleInfo); + + Status = gBS->HandleProtocol (gST->ConsoleInHandle, &gEfiSimpleTextInputExProtocolGuid, (VOID **) &TxtInEx); + if (!EFI_ERROR (Status)) { + while (ShellInfoObject.HaltOutput) { + + ShellInfoObject.HaltOutput = FALSE; + // + // just get some key + // + Status = gBS->WaitForEvent (1, &TxtInEx->WaitForKeyEx, &EventIndex); + ASSERT_EFI_ERROR (Status); + Status = TxtInEx->ReadKeyStrokeEx (TxtInEx, &KeyData); + if (EFI_ERROR(Status)) { + break; + } + + if ((KeyData.Key.UnicodeChar == L's') && (KeyData.Key.ScanCode == SCAN_NULL) && + ((KeyData.KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID | EFI_LEFT_CONTROL_PRESSED)) || + (KeyData.KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID | EFI_RIGHT_CONTROL_PRESSED)) + ) + ) { + ShellInfoObject.HaltOutput = TRUE; + } + } + } + + if (!ShellInfoObject.ConsoleInfo->Enabled) { + return (EFI_DEVICE_ERROR); + } else if (ShellInfoObject.PageBreakEnabled) { + return (ConsoleLoggerPrintWithPageBreak(WString, ConsoleInfo)); + } else { + return (ConsoleLoggerOutputStringSplit(WString, ConsoleInfo)); + } +} + +/** + Verifies that all characters in a Unicode string can be output to the + target device. + + @param[in] This Protocol instance pointer. + @param[in] WString The NULL-terminated Unicode string to be examined for the output + device(s). + + @retval EFI_SUCCESS The device(s) are capable of rendering the output string. + @retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be + rendered by one or more of the output devices mapped + by the EFI handle. + +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerTestString ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *WString + ) +{ + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This); + // + // Forward the request to the original ConOut + // + return (ConsoleInfo->OldConOut->TestString (ConsoleInfo->OldConOut, WString)); +} + +/** + Returns information for an available text mode that the output device(s) + supports. + + @param[in] This Protocol instance pointer. + @param[in] ModeNumber The mode number to return information on. + @param[out] Columns Upon return, the number of columns in the selected geometry + @param[out] Rows Upon return, the number of rows in the selected geometry + + @retval EFI_SUCCESS The requested mode information was returned. + @retval EFI_DEVICE_ERROR The device had an error and could not + complete the request. + @retval EFI_UNSUPPORTED The mode number was not valid. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerQueryMode ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber, + OUT UINTN *Columns, + OUT UINTN *Rows + ) +{ + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This); + // + // Forward the request to the original ConOut + // + return (ConsoleInfo->OldConOut->QueryMode ( + ConsoleInfo->OldConOut, + ModeNumber, + Columns, + Rows + )); +} + +/** + Sets the output device(s) to a specified mode. + + @param[in] This Protocol instance pointer. + @param[in] ModeNumber The mode number to set. + + + @retval EFI_SUCCESS The requested text mode was set. + @retval EFI_DEVICE_ERROR The device had an error and + could not complete the request. + @retval EFI_UNSUPPORTED The mode number was not valid. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerSetMode ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber + ) +{ + EFI_STATUS Status; + + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This); + + // + // Forward the request to the original ConOut + // + Status = ConsoleInfo->OldConOut->SetMode (ConsoleInfo->OldConOut, ModeNumber); + + // + // Check that the buffers are still correct for logging + // + if (!EFI_ERROR (Status)) { + ConsoleInfo->OurConOut.Mode = ConsoleInfo->OldConOut->Mode; + ConsoleLoggerResetBuffers(ConsoleInfo); + ConsoleInfo->OriginalStartRow = 0; + ConsoleInfo->CurrentStartRow = 0; + ConsoleInfo->OurConOut.ClearScreen (&ConsoleInfo->OurConOut); + } + + return Status; +} + +/** + Sets the background and foreground colors for the OutputString () and + ClearScreen () functions. + + @param[in] This Protocol instance pointer. + @param[in] Attribute The attribute to set. Bits 0..3 are the foreground color, and + bits 4..6 are the background color. All other bits are undefined + and must be zero. The valid Attributes are defined in this file. + + @retval EFI_SUCCESS The attribute was set. + @retval EFI_DEVICE_ERROR The device had an error and + could not complete the request. + @retval EFI_UNSUPPORTED The attribute requested is not defined. + +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerSetAttribute ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Attribute + ) +{ + EFI_STATUS Status; + + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This); + + // + // Forward the request to the original ConOut + // + Status = ConsoleInfo->OldConOut->SetAttribute (ConsoleInfo->OldConOut, Attribute); + + // + // Record console output history + // + if (!EFI_ERROR (Status)) { + ConsoleInfo->HistoryMode.Attribute = (INT32) Attribute; + } + + return Status; +} + +/** + Clears the output device(s) display to the currently selected background + color. + + @param[in] This Protocol instance pointer. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_DEVICE_ERROR The device had an error and + could not complete the request. + @retval EFI_UNSUPPORTED The output device is not in a valid text mode. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerClearScreen ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This + ) +{ + EFI_STATUS Status; + CHAR16 *Screen; + INT32 *Attributes; + UINTN Row; + UINTN Column; + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + + if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) { + return (EFI_UNSUPPORTED); + } + + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This); + + // + // Forward the request to the original ConOut + // + Status = ConsoleInfo->OldConOut->ClearScreen (ConsoleInfo->OldConOut); + + // + // Record console output history + // + if (!EFI_ERROR (Status)) { + Screen = &ConsoleInfo->Buffer[(ConsoleInfo->ColsPerScreen + 2) * ConsoleInfo->CurrentStartRow]; + Attributes = &ConsoleInfo->Attributes[ConsoleInfo->ColsPerScreen * ConsoleInfo->CurrentStartRow]; + for ( Row = ConsoleInfo->OriginalStartRow + ; Row < (ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount) + ; Row++ + ){ + for ( Column = 0 + ; Column < ConsoleInfo->ColsPerScreen + ; Column++ + , Screen++ + , Attributes++ + ){ + *Screen = L' '; + *Attributes = ConsoleInfo->OldConOut->Mode->Attribute; + } + // + // Skip the NULL on each column end in text buffer only + // + Screen += 2; + } + ConsoleInfo->HistoryMode.CursorColumn = 0; + ConsoleInfo->HistoryMode.CursorRow = 0; + } + + return Status; +} + +/** + Sets the current coordinates of the cursor position + + @param[in] This Protocol instance pointer. + @param[in] Column Column to put the cursor in. Must be between zero and Column returned from QueryMode + @param[in] Row Row to put the cursor in. Must be between zero and Row returned from QueryMode + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_DEVICE_ERROR The device had an error and + could not complete the request. + @retval EFI_UNSUPPORTED The output device is not in a valid text mode, or the + cursor position is invalid for the current mode. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerSetCursorPosition ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Column, + IN UINTN Row + ) +{ + EFI_STATUS Status; + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + + if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) { + return (EFI_UNSUPPORTED); + } + + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This); + // + // Forward the request to the original ConOut + // + Status = ConsoleInfo->OldConOut->SetCursorPosition ( + ConsoleInfo->OldConOut, + Column, + Row + ); + + // + // Record console output history + // + if (!EFI_ERROR (Status)) { + ConsoleInfo->HistoryMode.CursorColumn = (INT32)Column; + ConsoleInfo->HistoryMode.CursorRow = (INT32)(ConsoleInfo->OriginalStartRow + Row); + } + + return Status; +} + +/** + Makes the cursor visible or invisible + + @param[in] This Protocol instance pointer. + @param[in] Visible If TRUE, the cursor is set to be visible. If FALSE, the cursor is + set to be invisible. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_DEVICE_ERROR The device had an error and could not complete the + request, or the device does not support changing + the cursor mode. + @retval EFI_UNSUPPORTED The output device is not in a valid text mode. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerEnableCursor ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN Visible + ) +{ + EFI_STATUS Status; + + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This); + // + // Forward the request to the original ConOut + // + Status = ConsoleInfo->OldConOut->EnableCursor (ConsoleInfo->OldConOut, Visible); + + // + // Record console output history + // + if (!EFI_ERROR (Status)) { + ConsoleInfo->HistoryMode.CursorVisible = Visible; + } + + return Status; +} + +/** + Function to update and verify that the current buffers are correct. + + @param[in] ConsoleInfo The pointer to the instance of the console logger information. + + This will be used when a mode has changed or a reset occurred to verify all + history buffers. +**/ +EFI_STATUS +ConsoleLoggerResetBuffers( + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ) +{ + EFI_STATUS Status; + + if (ConsoleInfo->Buffer != NULL) { + FreePool(ConsoleInfo->Buffer); + ConsoleInfo->Buffer = NULL; + ConsoleInfo->BufferSize = 0; + } + if (ConsoleInfo->Attributes != NULL) { + FreePool(ConsoleInfo->Attributes); + ConsoleInfo->Attributes = NULL; + ConsoleInfo->AttribSize = 0; + } + + Status = gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &ConsoleInfo->ColsPerScreen, &ConsoleInfo->RowsPerScreen); + if (EFI_ERROR(Status)){ + return (Status); + } + + ConsoleInfo->BufferSize = (ConsoleInfo->ColsPerScreen + 2) * ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount * sizeof(ConsoleInfo->Buffer[0]); + ConsoleInfo->AttribSize = ConsoleInfo->ColsPerScreen * ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount * sizeof(ConsoleInfo->Attributes[0]); + + ConsoleInfo->Buffer = (CHAR16*)AllocateZeroPool(ConsoleInfo->BufferSize); + + if (ConsoleInfo->Buffer == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + ConsoleInfo->Attributes = (INT32*)AllocateZeroPool(ConsoleInfo->AttribSize); + if (ConsoleInfo->Attributes == NULL) { + FreePool(ConsoleInfo->Buffer); + ConsoleInfo->Buffer = NULL; + return (EFI_OUT_OF_RESOURCES); + } + + CopyMem (&ConsoleInfo->HistoryMode, ConsoleInfo->OldConOut->Mode, sizeof (EFI_SIMPLE_TEXT_OUTPUT_MODE)); + + return (EFI_SUCCESS); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ConsoleLogger.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ConsoleLogger.h new file mode 100644 index 00000000..c6899215 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ConsoleLogger.h @@ -0,0 +1,317 @@ +/** @file + Provides interface to shell console logger. + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _CONSOLE_LOGGER_HEADER_ +#define _CONSOLE_LOGGER_HEADER_ + +#include "Shell.h" + +#define CONSOLE_LOGGER_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('c', 'o', 'P', 'D') + +typedef struct _CONSOLE_LOGGER_PRIVATE_DATA{ + UINTN Signature; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL OurConOut; ///< the protocol we installed onto the system table + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *OldConOut; ///< old protocol to reinstall upon exiting + EFI_HANDLE OldConHandle; ///< old protocol handle + UINTN ScreenCount; ///< How many screens worth of data to save + CHAR16 *Buffer; ///< Buffer to save data + UINTN BufferSize; ///< size of buffer in bytes + + // start row is the top of the screen + UINTN OriginalStartRow; ///< What the originally visible start row was + UINTN CurrentStartRow; ///< what the currently visible start row is + + UINTN RowsPerScreen; ///< how many rows the screen can display + UINTN ColsPerScreen; ///< how many columns the screen can display + + INT32 *Attributes; ///< Buffer for Attribute to be saved for each character + UINTN AttribSize; ///< Size of Attributes in bytes + + EFI_SIMPLE_TEXT_OUTPUT_MODE HistoryMode; ///< mode of the history log + BOOLEAN Enabled; ///< Set to FALSE when a break is requested. + UINTN RowCounter; ///< Initial row of each print job. +} CONSOLE_LOGGER_PRIVATE_DATA; + +#define CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(a) CR (a, CONSOLE_LOGGER_PRIVATE_DATA, OurConOut, CONSOLE_LOGGER_PRIVATE_DATA_SIGNATURE) + +/** + Install our intermediate ConOut into the system table to + keep a log of all the info that is displayed to the user. + + @param[in] ScreensToSave Sets how many screen-worths of data to save. + @param[out] ConsoleInfo The object to pass into later functions. + + @retval EFI_SUCCESS The operation was successful. + @return other The operation failed. + + @sa ConsoleLoggerResetBuffers + @sa InstallProtocolInterface +**/ +EFI_STATUS +ConsoleLoggerInstall( + IN CONST UINTN ScreensToSave, + OUT CONSOLE_LOGGER_PRIVATE_DATA **ConsoleInfo + ); + +/** + Return the system to the state it was before InstallConsoleLogger + was installed. + + @param[in, out] ConsoleInfo The object from the install function. + + @retval EFI_SUCCESS The operation was successful + @return other The operation failed. This was from UninstallProtocolInterface. +**/ +EFI_STATUS +ConsoleLoggerUninstall( + IN OUT CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ); + +/** + Displays previously logged output back to the screen. + + This will scroll the screen forwards and backwards through the log of previous + output. If Rows is 0 then the size of 1/2 the screen will be scrolled. If Rows + is (UINTN)(-1) then the size of the screen will be scrolled. + + @param[in] Forward If TRUE then the log will be displayed forwards (scroll to newer). + If FALSE then the log will be displayed backwards (scroll to older). + @param[in] Rows Determines how many rows the log should scroll. + @param[in] ConsoleInfo The pointer to the instance of the console logger information. +**/ +EFI_STATUS +ConsoleLoggerDisplayHistory( + IN CONST BOOLEAN Forward, + IN CONST UINTN Rows, + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ); + +/** + Function to return to normal output whent he scrolling is complete. + @param[in] ConsoleInfo The pointer to the instance of the console logger information. + + @retval EFI_SUCCESS The operation was successful. + @return other The operation failed. See UpdateDisplayFromHistory. + + @sa UpdateDisplayFromHistory +**/ +EFI_STATUS +ConsoleLoggerStopHistory( + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ); + +/** + Updates the hidden ConOut to be displaying the correct stuff. + @param[in] ConsoleInfo The pointer to the instance of the console logger information. + + @retval EFI_SUCCESS The operation was successful. + @return other The operation failed. +**/ +EFI_STATUS +UpdateDisplayFromHistory( + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ); + +/** + Reset the text output device hardware and optionally run diagnostics + + @param This Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL + @param ExtendedVerification Indicates that a more extensive test may be performed + + @retval EFI_SUCCESS The text output device was reset. + @retval EFI_DEVICE_ERROR The text output device is not functioning correctly and + could not be reset. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerReset ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +/** + Write a Unicode string to the output device. + + @param[in] This Protocol instance pointer. + @param[in] WString The NULL-terminated Unicode string to be displayed on the output + device(s). All output devices must also support the Unicode + drawing defined in this file. + @retval EFI_SUCCESS The string was output to the device. + @retval EFI_DEVICE_ERROR The device reported an error while attempting to output + the text. + @retval EFI_UNSUPPORTED The output device's mode is not currently in a + defined text mode. + @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the + characters in the Unicode string could not be + rendered and were skipped. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerOutputString( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *WString + ); + +/** + Verifies that all characters in a Unicode string can be output to the + target device. + + @param[in] This Protocol instance pointer. + @param[in] WString The NULL-terminated Unicode string to be examined for the output + device(s). + + @retval EFI_SUCCESS The device(s) are capable of rendering the output string. + @retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be + rendered by one or more of the output devices mapped + by the EFI handle. + +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerTestString ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *WString + ); + +/** + Returns information for an available text mode that the output device(s) + supports. + + @param[in] This Protocol instance pointer. + @param[in] ModeNumber The mode number to return information on. + @param[out] Columns Upon return, the number of columns in the selected geometry + @param[out] Rows Upon return, the number of rows in the selected geometry + + @retval EFI_SUCCESS The requested mode information was returned. + @retval EFI_DEVICE_ERROR The device had an error and could not + complete the request. + @retval EFI_UNSUPPORTED The mode number was not valid. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerQueryMode ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber, + OUT UINTN *Columns, + OUT UINTN *Rows + ); + +/** + Sets the output device(s) to a specified mode. + + @param[in] This Protocol instance pointer. + @param[in] ModeNumber The mode number to set. + + + @retval EFI_SUCCESS The requested text mode was set. + @retval EFI_DEVICE_ERROR The device had an error and + could not complete the request. + @retval EFI_UNSUPPORTED The mode number was not valid. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerSetMode ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber + ); + +/** + Sets the background and foreground colors for the OutputString () and + ClearScreen () functions. + + @param[in] This Protocol instance pointer. + @param[in] Attribute The attribute to set. Bits 0..3 are the foreground color, and + bits 4..6 are the background color. All other bits are undefined + and must be zero. The valid Attributes are defined in this file. + + @retval EFI_SUCCESS The attribute was set. + @retval EFI_DEVICE_ERROR The device had an error and + could not complete the request. + @retval EFI_UNSUPPORTED The attribute requested is not defined. + +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerSetAttribute ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Attribute + ); + +/** + Clears the output device(s) display to the currently selected background + color. + + @param[in] This Protocol instance pointer. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_DEVICE_ERROR The device had an error and + could not complete the request. + @retval EFI_UNSUPPORTED The output device is not in a valid text mode. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerClearScreen ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This + ); + +/** + Sets the current coordinates of the cursor position. + + @param[in] This Protocol instance pointer. + @param[in] Column Column to put the cursor in. Must be between zero and Column returned from QueryMode + @param[in] Row Row to put the cursor in. Must be between zero and Row returned from QueryMode + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_DEVICE_ERROR The device had an error and + could not complete the request. + @retval EFI_UNSUPPORTED The output device is not in a valid text mode, or the + cursor position is invalid for the current mode. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerSetCursorPosition ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Column, + IN UINTN Row + ); + +/** + Makes the cursor visible or invisible + + @param[in] This Protocol instance pointer. + @param[in] Visible If TRUE, the cursor is set to be visible. If FALSE, the cursor is + set to be invisible. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_DEVICE_ERROR The device had an error and could not complete the + request, or the device does not support changing + the cursor mode. + @retval EFI_UNSUPPORTED The output device is not in a valid text mode. + +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerEnableCursor ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN Visible + ); + +/** + Function to update and verify that the current buffers are correct. + + @param[in] ConsoleInfo The pointer to the instance of the console logger information. + + This will be used when a mode has changed or a reset occurred to verify all + history buffers. +**/ +EFI_STATUS +ConsoleLoggerResetBuffers( + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ); + +#endif //_CONSOLE_LOGGER_HEADER_ + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ConsoleWrappers.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ConsoleWrappers.c new file mode 100644 index 00000000..f48e51ea --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ConsoleWrappers.c @@ -0,0 +1,508 @@ +/** @file + Function definitions for shell simple text in and out on top of file handles. + + (C) Copyright 2013 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Shell.h" + +extern BOOLEAN AsciiRedirection; + +typedef struct { + EFI_SIMPLE_TEXT_INPUT_PROTOCOL SimpleTextIn; + SHELL_FILE_HANDLE FileHandle; + EFI_HANDLE TheHandle; + UINT64 RemainingBytesOfInputFile; +} SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL; + +typedef struct { + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL SimpleTextOut; + SHELL_FILE_HANDLE FileHandle; + EFI_HANDLE TheHandle; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *OriginalSimpleTextOut; +} SHELL_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL; + +/** + Event notification function for EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey event + Signal the event if there is key available + + @param Event Indicates the event that invoke this function. + @param Context Indicates the calling context. + +**/ +VOID +EFIAPI +ConInWaitForKey ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + gBS->SignalEvent (Event); +} + +/** + Reset function for the fake simple text input. + + @param[in] This A pointer to the SimpleTextIn structure. + @param[in] ExtendedVerification TRUE for extra validation, FALSE otherwise. + + @retval EFI_SUCCESS The reset was successful. +**/ +EFI_STATUS +EFIAPI +FileBasedSimpleTextInReset( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + return (EFI_SUCCESS); +} + +/** + ReadKeyStroke function for the fake simple text input. + + @param[in] This A pointer to the SimpleTextIn structure. + @param[in, out] Key A pointer to the Key structure to fill. + + @retval EFI_SUCCESS The read was successful. +**/ +EFI_STATUS +EFIAPI +FileBasedSimpleTextInReadKeyStroke( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + IN OUT EFI_INPUT_KEY *Key + ) +{ + UINTN Size; + UINTN CharSize; + + // + // Verify the parameters + // + if (Key == NULL || This == NULL) { + return (EFI_INVALID_PARAMETER); + } + + // + // Check if we have any characters left in the stream. + // + if (((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)This)->RemainingBytesOfInputFile == 0) { + return (EFI_NOT_READY); + } + + Size = sizeof(CHAR16); + + if(!AsciiRedirection) { + CharSize = sizeof(CHAR16); + } else { + CharSize = sizeof(CHAR8); + } + // + // Decrement the amount of free space by Size or set to zero (for odd length files) + // + if (((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)This)->RemainingBytesOfInputFile > CharSize) { + ((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)This)->RemainingBytesOfInputFile -= CharSize; + } else { + ((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)This)->RemainingBytesOfInputFile = 0; + } + + Key->ScanCode = 0; + return (ShellInfoObject.NewEfiShellProtocol->ReadFile( + ((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)This)->FileHandle, + &Size, + &Key->UnicodeChar)); +} + +/** + Function to create a EFI_SIMPLE_TEXT_INPUT_PROTOCOL on top of a + SHELL_FILE_HANDLE to support redirecting input from a file. + + @param[in] FileHandleToUse The pointer to the SHELL_FILE_HANDLE to use. + @param[in] HandleLocation The pointer of a location to copy handle with protocol to. + + @retval NULL There was insufficient memory available. + @return A pointer to the allocated protocol structure; +**/ +EFI_SIMPLE_TEXT_INPUT_PROTOCOL* +CreateSimpleTextInOnFile( + IN SHELL_FILE_HANDLE FileHandleToUse, + IN EFI_HANDLE *HandleLocation + ) +{ + SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ProtocolToReturn; + EFI_STATUS Status; + UINT64 CurrentPosition; + UINT64 FileSize; + + if (HandleLocation == NULL || FileHandleToUse == NULL) { + return (NULL); + } + + ProtocolToReturn = AllocateZeroPool(sizeof(SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL)); + if (ProtocolToReturn == NULL) { + return (NULL); + } + + ShellGetFileSize (FileHandleToUse, &FileSize); + ShellGetFilePosition(FileHandleToUse, &CurrentPosition); + + // + // Initialize the protocol members + // + ProtocolToReturn->RemainingBytesOfInputFile = FileSize - CurrentPosition; + ProtocolToReturn->FileHandle = FileHandleToUse; + ProtocolToReturn->SimpleTextIn.Reset = FileBasedSimpleTextInReset; + ProtocolToReturn->SimpleTextIn.ReadKeyStroke = FileBasedSimpleTextInReadKeyStroke; + + Status = gBS->CreateEvent ( + EVT_NOTIFY_WAIT, + TPL_NOTIFY, + ConInWaitForKey, + &ProtocolToReturn->SimpleTextIn, + &ProtocolToReturn->SimpleTextIn.WaitForKey + ); + + if (EFI_ERROR(Status)) { + FreePool(ProtocolToReturn); + return (NULL); + } + ///@todo possibly also install SimpleTextInputEx on the handle at this point. + Status = gBS->InstallProtocolInterface( + &(ProtocolToReturn->TheHandle), + &gEfiSimpleTextInProtocolGuid, + EFI_NATIVE_INTERFACE, + &(ProtocolToReturn->SimpleTextIn)); + if (!EFI_ERROR(Status)) { + *HandleLocation = ProtocolToReturn->TheHandle; + return ((EFI_SIMPLE_TEXT_INPUT_PROTOCOL*)ProtocolToReturn); + } else { + FreePool(ProtocolToReturn); + return (NULL); + } +} + +/** + Function to close a EFI_SIMPLE_TEXT_INPUT_PROTOCOL on top of a + SHELL_FILE_HANDLE to support redirecting input from a file. + + @param[in] SimpleTextIn The pointer to the SimpleTextIn to close. + + @retval EFI_SUCCESS The object was closed. +**/ +EFI_STATUS +CloseSimpleTextInOnFile( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextIn + ) +{ + EFI_STATUS Status; + EFI_STATUS Status1; + + if (SimpleTextIn == NULL) { + return (EFI_INVALID_PARAMETER); + } + + Status = gBS->CloseEvent(((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)SimpleTextIn)->SimpleTextIn.WaitForKey); + + Status1 = gBS->UninstallProtocolInterface( + ((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL*)SimpleTextIn)->TheHandle, + &gEfiSimpleTextInProtocolGuid, + &(((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL*)SimpleTextIn)->SimpleTextIn)); + + FreePool(SimpleTextIn); + if (!EFI_ERROR(Status)) { + return (Status1); + } else { + return (Status); + } +} + +/** + Reset the text output device hardware and optionally run diagnostics. + + @param This pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL + @param ExtendedVerification Indicates that a more extensive test may be performed + + @retval EFI_SUCCESS The text output device was reset. +**/ +EFI_STATUS +EFIAPI +FileBasedSimpleTextOutReset ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + return (EFI_SUCCESS); +} + +/** + Verifies that all characters in a Unicode string can be output to the + target device. + + @param[in] This Protocol instance pointer. + @param[in] WString The NULL-terminated Unicode string to be examined. + + @retval EFI_SUCCESS The device(s) are capable of rendering the output string. +**/ +EFI_STATUS +EFIAPI +FileBasedSimpleTextOutTestString ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *WString + ) +{ + return (EFI_SUCCESS); +} + +/** + Returns information for an available text mode that the output device(s) + supports. + + @param[in] This Protocol instance pointer. + @param[in] ModeNumber The mode number to return information on. + @param[out] Columns Upon return, the number of columns in the selected geometry + @param[out] Rows Upon return, the number of rows in the selected geometry + + @retval EFI_UNSUPPORTED The mode number was not valid. +**/ +EFI_STATUS +EFIAPI +FileBasedSimpleTextOutQueryMode ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber, + OUT UINTN *Columns, + OUT UINTN *Rows + ) +{ + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *PassThruProtocol; + + PassThruProtocol = ((SHELL_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)This)->OriginalSimpleTextOut; + + // Pass the QueryMode call thru to the original SimpleTextOutProtocol + return (PassThruProtocol->QueryMode( + PassThruProtocol, + ModeNumber, + Columns, + Rows)); +} + +/** + Sets the output device(s) to a specified mode. + + @param[in] This Protocol instance pointer. + @param[in] ModeNumber The mode number to set. + + @retval EFI_UNSUPPORTED The mode number was not valid. +**/ +EFI_STATUS +EFIAPI +FileBasedSimpleTextOutSetMode ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber + ) +{ + return (EFI_UNSUPPORTED); +} + +/** + Sets the background and foreground colors for the OutputString () and + ClearScreen () functions. + + @param[in] This Protocol instance pointer. + @param[in] Attribute The attribute to set. Bits 0..3 are the foreground color, and + bits 4..6 are the background color. All other bits are undefined + and must be zero. The valid Attributes are defined in this file. + + @retval EFI_SUCCESS The attribute was set. +**/ +EFI_STATUS +EFIAPI +FileBasedSimpleTextOutSetAttribute ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Attribute + ) +{ + return (EFI_SUCCESS); +} + +/** + Clears the output device(s) display to the currently selected background + color. + + @param[in] This Protocol instance pointer. + + @retval EFI_UNSUPPORTED The output device is not in a valid text mode. +**/ +EFI_STATUS +EFIAPI +FileBasedSimpleTextOutClearScreen ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This + ) +{ + return (EFI_SUCCESS); +} + +/** + Sets the current coordinates of the cursor position + + @param[in] This Protocol instance pointer. + @param[in] Column Column to put the cursor in. Must be between zero and Column returned from QueryMode + @param[in] Row Row to put the cursor in. Must be between zero and Row returned from QueryMode + + @retval EFI_SUCCESS The operation completed successfully. +**/ +EFI_STATUS +EFIAPI +FileBasedSimpleTextOutSetCursorPosition ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Column, + IN UINTN Row + ) +{ + return (EFI_SUCCESS); +} + +/** + Makes the cursor visible or invisible + + @param[in] This Protocol instance pointer. + @param[in] Visible If TRUE, the cursor is set to be visible. If FALSE, the cursor is + set to be invisible. + + @retval EFI_SUCCESS The operation completed successfully. +**/ +EFI_STATUS +EFIAPI +FileBasedSimpleTextOutEnableCursor ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN Visible + ) +{ + return (EFI_SUCCESS); +} + +/** + Write a Unicode string to the output device. + + @param[in] This Protocol instance pointer. + @param[in] WString The NULL-terminated Unicode string to be displayed on the output + device(s). All output devices must also support the Unicode + drawing defined in this file. + @retval EFI_SUCCESS The string was output to the device. + @retval EFI_DEVICE_ERROR The device reported an error while attempting to output + the text. + @retval EFI_UNSUPPORTED The output device's mode is not currently in a + defined text mode. + @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the + characters in the Unicode string could not be + rendered and were skipped. +**/ +EFI_STATUS +EFIAPI +FileBasedSimpleTextOutOutputString ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *WString + ) +{ + UINTN Size; + Size = StrLen(WString) * sizeof(CHAR16); + return (ShellInfoObject.NewEfiShellProtocol->WriteFile( + ((SHELL_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)This)->FileHandle, + &Size, + WString)); +} + +/** + Function to create a EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL on top of a + SHELL_FILE_HANDLE to support redirecting output from a file. + + @param[in] FileHandleToUse The pointer to the SHELL_FILE_HANDLE to use. + @param[in] HandleLocation The pointer of a location to copy handle with protocol to. + @param[in] OriginalProtocol The pointer to the original output protocol for pass thru of functions. + + @retval NULL There was insufficient memory available. + @return A pointer to the allocated protocol structure; +**/ +EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL* +CreateSimpleTextOutOnFile( + IN SHELL_FILE_HANDLE FileHandleToUse, + IN EFI_HANDLE *HandleLocation, + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *OriginalProtocol + ) +{ + SHELL_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ProtocolToReturn; + EFI_STATUS Status; + + if (HandleLocation == NULL || FileHandleToUse == NULL) { + return (NULL); + } + + ProtocolToReturn = AllocateZeroPool(sizeof(SHELL_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL)); + if (ProtocolToReturn == NULL) { + return (NULL); + } + ProtocolToReturn->FileHandle = FileHandleToUse; + ProtocolToReturn->OriginalSimpleTextOut = OriginalProtocol; + ProtocolToReturn->SimpleTextOut.Reset = FileBasedSimpleTextOutReset; + ProtocolToReturn->SimpleTextOut.TestString = FileBasedSimpleTextOutTestString; + ProtocolToReturn->SimpleTextOut.QueryMode = FileBasedSimpleTextOutQueryMode; + ProtocolToReturn->SimpleTextOut.SetMode = FileBasedSimpleTextOutSetMode; + ProtocolToReturn->SimpleTextOut.SetAttribute = FileBasedSimpleTextOutSetAttribute; + ProtocolToReturn->SimpleTextOut.ClearScreen = FileBasedSimpleTextOutClearScreen; + ProtocolToReturn->SimpleTextOut.SetCursorPosition = FileBasedSimpleTextOutSetCursorPosition; + ProtocolToReturn->SimpleTextOut.EnableCursor = FileBasedSimpleTextOutEnableCursor; + ProtocolToReturn->SimpleTextOut.OutputString = FileBasedSimpleTextOutOutputString; + ProtocolToReturn->SimpleTextOut.Mode = AllocateZeroPool(sizeof(EFI_SIMPLE_TEXT_OUTPUT_MODE)); + if (ProtocolToReturn->SimpleTextOut.Mode == NULL) { + FreePool(ProtocolToReturn); + return (NULL); + } + ProtocolToReturn->SimpleTextOut.Mode->MaxMode = OriginalProtocol->Mode->MaxMode; + ProtocolToReturn->SimpleTextOut.Mode->Mode = OriginalProtocol->Mode->Mode; + ProtocolToReturn->SimpleTextOut.Mode->Attribute = OriginalProtocol->Mode->Attribute; + ProtocolToReturn->SimpleTextOut.Mode->CursorColumn = OriginalProtocol->Mode->CursorColumn; + ProtocolToReturn->SimpleTextOut.Mode->CursorRow = OriginalProtocol->Mode->CursorRow; + ProtocolToReturn->SimpleTextOut.Mode->CursorVisible = OriginalProtocol->Mode->CursorVisible; + + Status = gBS->InstallProtocolInterface( + &(ProtocolToReturn->TheHandle), + &gEfiSimpleTextOutProtocolGuid, + EFI_NATIVE_INTERFACE, + &(ProtocolToReturn->SimpleTextOut)); + if (!EFI_ERROR(Status)) { + *HandleLocation = ProtocolToReturn->TheHandle; + return ((EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL*)ProtocolToReturn); + } else { + SHELL_FREE_NON_NULL(ProtocolToReturn->SimpleTextOut.Mode); + SHELL_FREE_NON_NULL(ProtocolToReturn); + return (NULL); + } +} + +/** + Function to close a EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL on top of a + SHELL_FILE_HANDLE to support redirecting output from a file. + + @param[in] SimpleTextOut The pointer to the SimpleTextOUT to close. + + @retval EFI_SUCCESS The object was closed. +**/ +EFI_STATUS +CloseSimpleTextOutOnFile( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut + ) +{ + EFI_STATUS Status; + if (SimpleTextOut == NULL) { + return (EFI_INVALID_PARAMETER); + } + Status = gBS->UninstallProtocolInterface( + ((SHELL_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL*)SimpleTextOut)->TheHandle, + &gEfiSimpleTextOutProtocolGuid, + &(((SHELL_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL*)SimpleTextOut)->SimpleTextOut)); + FreePool(SimpleTextOut->Mode); + FreePool(SimpleTextOut); + return (Status); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ConsoleWrappers.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ConsoleWrappers.h new file mode 100644 index 00000000..a4a07989 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ConsoleWrappers.h @@ -0,0 +1,74 @@ +/** @file + Function definitions for shell simple text in and out on top of file handles. + + (C) Copyright 2013 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SHELL_CONSOLE_WRAPPERS_HEADER_ +#define _SHELL_CONSOLE_WRAPPERS_HEADER_ + +/** + Function to create a EFI_SIMPLE_TEXT_INPUT_PROTOCOL on top of a + SHELL_FILE_HANDLE to support redirecting input from a file. + + @param[in] FileHandleToUse The pointer to the SHELL_FILE_HANDLE to use. + @param[in] HandleLocation The pointer of a location to copy handle with protocol to. + + @retval NULL There was insufficient memory available. + @return A pointer to the allocated protocol structure; +**/ +EFI_SIMPLE_TEXT_INPUT_PROTOCOL* +CreateSimpleTextInOnFile( + IN SHELL_FILE_HANDLE FileHandleToUse, + IN EFI_HANDLE *HandleLocation + ); + +/** + Function to close a EFI_SIMPLE_TEXT_INPUT_PROTOCOL on top of a + SHELL_FILE_HANDLE to support redirecting input from a file. + + @param[in] SimpleTextIn The pointer to the SimpleTextIn to close. + + @retval EFI_SUCCESS The object was closed. +**/ +EFI_STATUS +CloseSimpleTextInOnFile( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextIn + ); + +/** + Function to create a EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL on top of a + SHELL_FILE_HANDLE to support redirecting output from a file. + + @param[in] FileHandleToUse The pointer to the SHELL_FILE_HANDLE to use. + @param[in] HandleLocation The pointer of a location to copy handle with protocol to. + @param[in] OriginalProtocol The pointer to the original output protocol for pass thru of functions. + + @retval NULL There was insufficient memory available. + @return A pointer to the allocated protocol structure; +**/ +EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL* +CreateSimpleTextOutOnFile( + IN SHELL_FILE_HANDLE FileHandleToUse, + IN EFI_HANDLE *HandleLocation, + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *OriginalProtocol + ); + +/** + Function to close a EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL on top of a + SHELL_FILE_HANDLE to support redirecting output from a file. + + @param[in] SimpleTextOut The pointer to the SimpleTextOUT to close. + + @retval EFI_SUCCESS The object was closed. +**/ +EFI_STATUS +CloseSimpleTextOutOnFile( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut + ); + +#endif //_SHELL_CONSOLE_WRAPPERS_HEADER_ + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/FileHandleInternal.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/FileHandleInternal.h new file mode 100644 index 00000000..3b36a8e7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/FileHandleInternal.h @@ -0,0 +1,59 @@ +/** @file + internal worker functions for FileHandleWrappers to use + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _FILE_HANDLE_INTERNAL_HEADER_ +#define _FILE_HANDLE_INTERNAL_HEADER_ + +/** + Move the cursor position one character backward. + + @param[in] LineLength Length of a line. Get it by calling QueryMode + @param[in, out] Column Current column of the cursor position + @param[in, out] Row Current row of the cursor position +**/ +VOID +MoveCursorBackward ( + IN UINTN LineLength, + IN OUT UINTN *Column, + IN OUT UINTN *Row + ); + +/** + Move the cursor position one character forward. + + @param[in] LineLength Length of a line. + @param[in] TotalRow Total row of a screen + @param[in, out] Column Current column of the cursor position + @param[in, out] Row Current row of the cursor position +**/ +VOID +MoveCursorForward ( + IN UINTN LineLength, + IN UINTN TotalRow, + IN OUT UINTN *Column, + IN OUT UINTN *Row + ); + +/** + Prints out each previously typed command in the command list history log. + + When each screen is full it will pause for a key before continuing. + + @param[in] TotalCols How many columns are on the screen + @param[in] TotalRows How many rows are on the screen + @param[in] StartColumn which column to start at +**/ +VOID +PrintCommandHistory ( + IN CONST UINTN TotalCols, + IN CONST UINTN TotalRows, + IN CONST UINTN StartColumn + ); + +#endif //_FILE_HANDLE_INTERNAL_HEADER_ + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/FileHandleWrappers.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/FileHandleWrappers.c new file mode 100644 index 00000000..e2f0ad39 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/FileHandleWrappers.c @@ -0,0 +1,2154 @@ +/** @file + EFI_FILE_PROTOCOL wrappers for other items (Like Environment Variables, + StdIn, StdOut, StdErr, etc...). + + Copyright 2016 Dell Inc. + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2013 Hewlett-Packard Development Company, L.P.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Shell.h" +#include "FileHandleInternal.h" + +#define MEM_WRITE_REALLOC_OVERHEAD 1024 + +/** + File style interface for console (Open). + + @param[in] This Ignored. + @param[out] NewHandle Ignored. + @param[in] FileName Ignored. + @param[in] OpenMode Ignored. + @param[in] Attributes Ignored. + + @retval EFI_NOT_FOUND +**/ +EFI_STATUS +EFIAPI +FileInterfaceOpenNotFound( + IN EFI_FILE_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes + ) +{ + return (EFI_NOT_FOUND); +} + +/** + File style interface for console (Close, Delete, & Flush) + + @param[in] This Ignored. + + @retval EFI_SUCCESS +**/ +EFI_STATUS +EFIAPI +FileInterfaceNopGeneric( + IN EFI_FILE_PROTOCOL *This + ) +{ + return (EFI_SUCCESS); +} + +/** + File style interface for console (GetPosition). + + @param[in] This Ignored. + @param[out] Position Ignored. + + @retval EFI_UNSUPPORTED +**/ +EFI_STATUS +EFIAPI +FileInterfaceNopGetPosition( + IN EFI_FILE_PROTOCOL *This, + OUT UINT64 *Position + ) +{ + return (EFI_UNSUPPORTED); +} + +/** + File style interface for console (SetPosition). + + @param[in] This Ignored. + @param[in] Position Ignored. + + @retval EFI_UNSUPPORTED +**/ +EFI_STATUS +EFIAPI +FileInterfaceNopSetPosition( + IN EFI_FILE_PROTOCOL *This, + IN UINT64 Position + ) +{ + return (EFI_UNSUPPORTED); +} + +/** + File style interface for console (GetInfo). + + @param[in] This Ignored. + @param[in] InformationType Ignored. + @param[in, out] BufferSize Ignored. + @param[out] Buffer Ignored. + + @retval EFI_UNSUPPORTED +**/ +EFI_STATUS +EFIAPI +FileInterfaceNopGetInfo( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + return (EFI_UNSUPPORTED); +} + +/** + File style interface for console (SetInfo). + + @param[in] This Ignored. + @param[in] InformationType Ignored. + @param[in] BufferSize Ignored. + @param[in] Buffer Ignored. + + @retval EFI_UNSUPPORTED +**/ +EFI_STATUS +EFIAPI +FileInterfaceNopSetInfo( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + return (EFI_UNSUPPORTED); +} + +/** + File style interface for StdOut (Write). + + Writes data to the screen. + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + @param[in, out] BufferSize Size in bytes of Buffer. + @param[in] Buffer The pointer to the buffer to write. + + @retval EFI_UNSUPPORTED No output console is supported. + @return A return value from gST->ConOut->OutputString. +**/ +EFI_STATUS +EFIAPI +FileInterfaceStdOutWrite( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) { + return (EFI_UNSUPPORTED); + } + if (*((CHAR16 *)Buffer) == gUnicodeFileTag) { + return (gST->ConOut->OutputString(gST->ConOut, (CHAR16 *)Buffer + 1)); + } + return (gST->ConOut->OutputString(gST->ConOut, Buffer)); +} + +/** + File style interface for StdIn (Write). + + @param[in] This Ignored. + @param[in, out] BufferSize Ignored. + @param[in] Buffer Ignored. + + @retval EFI_UNSUPPORTED +**/ +EFI_STATUS +EFIAPI +FileInterfaceStdInWrite( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + return (EFI_UNSUPPORTED); +} + +/** + File style interface for console StdErr (Write). + + Writes error to the error output. + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + @param[in, out] BufferSize Size in bytes of Buffer. + @param[in] Buffer The pointer to the buffer to write. + + @return A return value from gST->StdErr->OutputString. +**/ +EFI_STATUS +EFIAPI +FileInterfaceStdErrWrite( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + return (gST->StdErr->OutputString(gST->StdErr, Buffer)); +} + +/** + File style interface for console StdOut (Read). + + @param[in] This Ignored. + @param[in, out] BufferSize Ignored. + @param[out] Buffer Ignored. + + @retval EFI_UNSUPPORTED +**/ +EFI_STATUS +EFIAPI +FileInterfaceStdOutRead( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + return (EFI_UNSUPPORTED); +} + +/** + File style interface for console StdErr (Read). + + @param[in] This Ignored. + @param[in, out] BufferSize Ignored. + @param[out] Buffer Ignored. + + @retval EFI_UNSUPPORTED Always. +**/ +EFI_STATUS +EFIAPI +FileInterfaceStdErrRead( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + return (EFI_UNSUPPORTED); +} + +/** + File style interface for NUL file (Read). + + @param[in] This Ignored. + @param[in, out] BufferSize Poiner to 0 upon return. + @param[out] Buffer Ignored. + + @retval EFI_SUCCESS Always. +**/ +EFI_STATUS +EFIAPI +FileInterfaceNulRead( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + *BufferSize = 0; + return (EFI_SUCCESS); +} + +/** + File style interface for NUL file (Write). + + @param[in] This Ignored. + @param[in, out] BufferSize Ignored. + @param[in] Buffer Ignored. + + @retval EFI_SUCCESS +**/ +EFI_STATUS +EFIAPI +FileInterfaceNulWrite( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + return (EFI_SUCCESS); +} + +/** + Create the TAB completion list. + + @param[in] InputString The command line to expand. + @param[in] StringLen Length of the command line. + @param[in] BufferSize Buffer size. + @param[in, out] TabCompletionList Return the TAB completion list. + @param[in, out] TabUpdatePos Return the TAB update position. +**/ +EFI_STATUS +CreateTabCompletionList ( + IN CONST CHAR16 *InputString, + IN CONST UINTN StringLen, + IN CONST UINTN BufferSize, + IN OUT EFI_SHELL_FILE_INFO **TabCompletionList, + IN OUT UINTN *TabUpdatePos +) +{ + BOOLEAN InQuotation; + UINTN TabPos; + UINTN Index; + CONST CHAR16 *Cwd; + EFI_STATUS Status; + CHAR16 *TabStr; + EFI_SHELL_FILE_INFO *FileList; + EFI_SHELL_FILE_INFO *FileInfo; + EFI_SHELL_FILE_INFO *TempFileInfo; + + // + // Allocate buffers + // + TabStr = AllocateZeroPool (BufferSize); + if (TabStr == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // handle auto complete of file and directory names... + // E.g.: cd fs0:\EFI\Bo + // ^ ^ + // TabPos TabUpdatePos + // + TabPos = 0; + *TabUpdatePos = 0; + FileList = NULL; + InQuotation = FALSE; + for (Index = 0; Index < StringLen; Index++) { + switch (InputString[Index]) { + case L'\"': + InQuotation = (BOOLEAN) (!InQuotation); + break; + + case L' ': + if (!InQuotation) { + TabPos = Index + 1; + *TabUpdatePos = TabPos; + } + break; + + case L':': + // + // handle the case "fs0:" + // Update the TabUpdatePos as well. + // + case L'\\': + *TabUpdatePos = Index + 1; + break; + + default: + break; + } + } + + if (StrStr (InputString + TabPos, L":") == NULL) { + // + // If file path doesn't contain ":", ... + // + Cwd = ShellInfoObject.NewEfiShellProtocol->GetCurDir (NULL); + if (Cwd != NULL) { + if (InputString[TabPos] != L'\\') { + // + // and it doesn't begin with "\\", it's a path relative to current directory. + // TabStr = "\\" + // + StrnCpyS (TabStr, BufferSize / sizeof (CHAR16), Cwd, (BufferSize) / sizeof (CHAR16) - 1); + StrCatS (TabStr, (BufferSize) / sizeof (CHAR16), L"\\"); + } else { + // + // and it begins with "\\", it's a path pointing to root directory of current map. + // TabStr = "fsx:" + // + Index = StrStr (Cwd, L":") - Cwd + 1; + StrnCpyS (TabStr, BufferSize / sizeof (CHAR16), Cwd, Index); + } + } + } + StrnCatS (TabStr, (BufferSize) / sizeof (CHAR16), InputString + TabPos, StringLen - TabPos); + StrnCatS (TabStr, (BufferSize) / sizeof (CHAR16), L"*", (BufferSize) / sizeof (CHAR16) - 1 - StrLen (TabStr)); + Status = ShellInfoObject.NewEfiShellProtocol->FindFiles(TabStr, &FileList); + + // + // Filter out the non-directory for "CD" command + // Filter "." and ".." for all + // + if (!EFI_ERROR (Status) && FileList != NULL) { + // + // Skip the spaces in the beginning + // + while (*InputString == L' ') { + InputString++; + } + + for (FileInfo = (EFI_SHELL_FILE_INFO *) GetFirstNode (&FileList->Link); !IsNull (&FileList->Link, &FileInfo->Link); ) { + if (((StrCmp (FileInfo->FileName, L".") == 0) || (StrCmp (FileInfo->FileName, L"..") == 0)) || + (((InputString[0] == L'c' || InputString[0] == L'C') && (InputString[1] == L'd' || InputString[1] == L'D')) && + (ShellIsDirectory (FileInfo->FullName) != EFI_SUCCESS))) { + TempFileInfo = FileInfo; + FileInfo = (EFI_SHELL_FILE_INFO *) RemoveEntryList (&FileInfo->Link); + InternalFreeShellFileInfoNode (TempFileInfo); + } else { + FileInfo = (EFI_SHELL_FILE_INFO *) GetNextNode (&FileList->Link, &FileInfo->Link); + } + } + } + + if (FileList != NULL && !IsListEmpty (&FileList->Link)) { + Status = EFI_SUCCESS; + } else { + ShellInfoObject.NewEfiShellProtocol->FreeFileList (&FileList); + Status = EFI_NOT_FOUND; + } + + FreePool (TabStr); + + *TabCompletionList = FileList; + return Status; +} + +/** + File style interface for console (Read). + + This will return a single line of input from the console. + + @param This A pointer to the EFI_FILE_PROTOCOL instance that is the + file handle to read data from. Not used. + @param BufferSize On input, the size of the Buffer. On output, the amount + of data returned in Buffer. In both cases, the size is + measured in bytes. + @param Buffer The buffer into which the data is read. + + + @retval EFI_SUCCESS The data was read. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_DEVICE_ERROR An attempt was made to read from a deleted file. + @retval EFI_DEVICE_ERROR On entry, the current file position is beyond the end of the file. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory + entry. BufferSize has been updated with the size + needed to complete the request. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +EFIAPI +FileInterfaceStdInRead( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + CHAR16 *CurrentString; + BOOLEAN Done; + UINTN TabUpdatePos; // Start index of the string updated by TAB stroke + UINTN Column; // Column of current cursor + UINTN Row; // Row of current cursor + UINTN StartColumn; // Column at the beginning of the line + UINTN Update; // Line index for update + UINTN Delete; // Num of chars to delete from console after update + UINTN StringLen; // Total length of the line + UINTN StringCurPos; // Line index corresponding to the cursor + UINTN MaxStr; // Maximum possible line length + UINTN TotalColumn; // Num of columns in the console + UINTN TotalRow; // Num of rows in the console + UINTN SkipLength; + UINTN OutputLength; // Length of the update string + UINTN TailRow; // Row of end of line + UINTN TailColumn; // Column of end of line + EFI_INPUT_KEY Key; + + BUFFER_LIST *LinePos; + BUFFER_LIST *NewPos; + BOOLEAN InScrolling; + EFI_STATUS Status; + BOOLEAN InTabScrolling; // Whether in TAB-completion state + EFI_SHELL_FILE_INFO *TabCompleteList; + EFI_SHELL_FILE_INFO *TabCurrent; + UINTN EventIndex; + CHAR16 *TabOutputStr; + + // + // If buffer is not large enough to hold a CHAR16, return minimum buffer size + // + if (*BufferSize < sizeof (CHAR16) * 2) { + *BufferSize = sizeof (CHAR16) * 2; + return (EFI_BUFFER_TOO_SMALL); + } + + Done = FALSE; + CurrentString = Buffer; + StringLen = 0; + StringCurPos = 0; + OutputLength = 0; + Update = 0; + Delete = 0; + LinePos = NewPos = (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory); + InScrolling = FALSE; + InTabScrolling = FALSE; + Status = EFI_SUCCESS; + TabOutputStr = NULL; + TabUpdatePos = 0; + TabCompleteList = NULL; + TabCurrent = NULL; + + // + // Get the screen setting and the current cursor location + // + Column = StartColumn = gST->ConOut->Mode->CursorColumn; + Row = gST->ConOut->Mode->CursorRow; + gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &TotalColumn, &TotalRow); + + // + // Limit the line length to the buffer size or the minimum size of the + // screen. (The smaller takes effect) + // + MaxStr = TotalColumn * (TotalRow - 1) - StartColumn; + if (MaxStr > *BufferSize / sizeof (CHAR16)) { + MaxStr = *BufferSize / sizeof (CHAR16); + } + ZeroMem (CurrentString, MaxStr * sizeof (CHAR16)); + do { + // + // Read a key + // + gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex); + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + if (EFI_ERROR (Status)) { + + if (Status == EFI_NOT_READY) + continue; + + ZeroMem (CurrentString, MaxStr * sizeof(CHAR16)); + StringLen = 0; + break; + } + + // + // Press PageUp or PageDown to scroll the history screen up or down. + // Press any other key to quit scrolling. + // + if (Key.UnicodeChar == 0 && (Key.ScanCode == SCAN_PAGE_UP || Key.ScanCode == SCAN_PAGE_DOWN)) { + if (Key.ScanCode == SCAN_PAGE_UP) { + ConsoleLoggerDisplayHistory(FALSE, 0, ShellInfoObject.ConsoleInfo); + } else if (Key.ScanCode == SCAN_PAGE_DOWN) { + ConsoleLoggerDisplayHistory(TRUE, 0, ShellInfoObject.ConsoleInfo); + } + + InScrolling = TRUE; + } else { + if (InScrolling) { + ConsoleLoggerStopHistory(ShellInfoObject.ConsoleInfo); + InScrolling = FALSE; + } + } + + // + // If we are quitting TAB scrolling... + // + if (InTabScrolling && Key.UnicodeChar != CHAR_TAB) { + if (TabCompleteList != NULL) { + ShellInfoObject.NewEfiShellProtocol->FreeFileList (&TabCompleteList); + DEBUG_CODE(TabCompleteList = NULL;); + } + InTabScrolling = FALSE; + } + + switch (Key.UnicodeChar) { + case CHAR_CARRIAGE_RETURN: + // + // All done, print a newline at the end of the string + // + TailRow = Row + (StringLen - StringCurPos + Column) / TotalColumn; + TailColumn = (StringLen - StringCurPos + Column) % TotalColumn; + ShellPrintEx ((INT32)TailColumn, (INT32)TailRow, L"%N\n"); + Done = TRUE; + break; + + case CHAR_BACKSPACE: + if (StringCurPos != 0) { + // + // If not move back beyond string beginning, move all characters behind + // the current position one character forward + // + StringCurPos--; + Update = StringCurPos; + Delete = 1; + CopyMem (CurrentString + StringCurPos, CurrentString + StringCurPos + 1, sizeof (CHAR16) * (StringLen - StringCurPos)); + + // + // Adjust the current column and row + // + MoveCursorBackward (TotalColumn, &Column, &Row); + } + break; + + case CHAR_TAB: + if (!InTabScrolling) { + TabCurrent = NULL; + // + // Initialize a tab complete operation. + // + Status = CreateTabCompletionList (CurrentString, StringLen, *BufferSize, &TabCompleteList, &TabUpdatePos); + if (!EFI_ERROR(Status)) { + InTabScrolling = TRUE; + } + + // + // We do not set up the replacement. + // The next section will do that. + // + } + + if (InTabScrolling) { + // + // We are in a tab complete operation. + // set up the next replacement. + // + ASSERT(TabCompleteList != NULL); + if (TabCurrent == NULL) { + TabCurrent = (EFI_SHELL_FILE_INFO*) GetFirstNode (&TabCompleteList->Link); + } else { + TabCurrent = (EFI_SHELL_FILE_INFO*) GetNextNode (&TabCompleteList->Link, &TabCurrent->Link); + } + + // + // Skip over the empty list beginning node + // + if (IsNull(&TabCompleteList->Link, &TabCurrent->Link)) { + TabCurrent = (EFI_SHELL_FILE_INFO*) GetNextNode (&TabCompleteList->Link, &TabCurrent->Link); + } + } + break; + + default: + if (Key.UnicodeChar >= ' ') { + // + // If we are at the buffer's end, drop the key + // + if (StringLen == MaxStr - 1 && (ShellInfoObject.ViewingSettings.InsertMode || StringCurPos == StringLen)) { + break; + } + // + // If in insert mode, make space by moving each other character 1 + // space higher in the array + // + if (ShellInfoObject.ViewingSettings.InsertMode) { + CopyMem(CurrentString + StringCurPos + 1, CurrentString + StringCurPos, (StringLen - StringCurPos)*sizeof(CurrentString[0])); + } + + CurrentString[StringCurPos] = Key.UnicodeChar; + Update = StringCurPos; + + StringCurPos += 1; + OutputLength = 1; + } + break; + + case 0: + switch (Key.ScanCode) { + case SCAN_DELETE: + // + // Move characters behind current position one character forward + // + if (StringLen != 0) { + Update = StringCurPos; + Delete = 1; + CopyMem (CurrentString + StringCurPos, CurrentString + StringCurPos + 1, sizeof (CHAR16) * (StringLen - StringCurPos)); + } + break; + + case SCAN_UP: + // + // Prepare to print the previous command + // + NewPos = (BUFFER_LIST*)GetPreviousNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link); + if (IsNull(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link)) { + NewPos = (BUFFER_LIST*)GetPreviousNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link); + } + break; + + case SCAN_DOWN: + // + // Prepare to print the next command + // + NewPos = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link); + if (NewPos == (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory)) { + NewPos = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link); + } + break; + + case SCAN_LEFT: + // + // Adjust current cursor position + // + if (StringCurPos != 0) { + --StringCurPos; + MoveCursorBackward (TotalColumn, &Column, &Row); + } + break; + + case SCAN_RIGHT: + // + // Adjust current cursor position + // + if (StringCurPos < StringLen) { + ++StringCurPos; + MoveCursorForward (TotalColumn, TotalRow, &Column, &Row); + } + break; + + case SCAN_HOME: + // + // Move current cursor position to the beginning of the command line + // + Row -= (StringCurPos + StartColumn) / TotalColumn; + Column = StartColumn; + StringCurPos = 0; + break; + + case SCAN_END: + // + // Move current cursor position to the end of the command line + // + TailRow = Row + (StringLen - StringCurPos + Column) / TotalColumn; + TailColumn = (StringLen - StringCurPos + Column) % TotalColumn; + Row = TailRow; + Column = TailColumn; + StringCurPos = StringLen; + break; + + case SCAN_ESC: + // + // Prepare to clear the current command line + // + CurrentString[0] = 0; + Update = 0; + Delete = StringLen; + Row -= (StringCurPos + StartColumn) / TotalColumn; + Column = StartColumn; + OutputLength = 0; + break; + + case SCAN_INSERT: + // + // Toggle the SEnvInsertMode flag + // + ShellInfoObject.ViewingSettings.InsertMode = (BOOLEAN)!ShellInfoObject.ViewingSettings.InsertMode; + break; + + case SCAN_F7: + // + // Print command history + // + PrintCommandHistory (TotalColumn, TotalRow, 4); + *CurrentString = CHAR_NULL; + Done = TRUE; + break; + } + } + + if (Done) { + break; + } + + // + // If we are in auto-complete mode, we are preparing to print + // the next file or directory name + // + if (InTabScrolling) { + TabOutputStr = AllocateZeroPool (*BufferSize); + if (TabOutputStr == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } + } + + if (InTabScrolling && TabOutputStr != NULL) { + + // + // Adjust the column and row to the start of TAB-completion string. + // + Column = (StartColumn + TabUpdatePos) % TotalColumn; + Row -= (StartColumn + StringCurPos) / TotalColumn - (StartColumn + TabUpdatePos) / TotalColumn; + OutputLength = StrLen (TabCurrent->FileName); + // + // if the output string contains blank space, quotation marks L'\"' + // should be added to the output. + // + if (StrStr(TabCurrent->FileName, L" ") != NULL){ + TabOutputStr[0] = L'\"'; + CopyMem (TabOutputStr + 1, TabCurrent->FileName, OutputLength * sizeof (CHAR16)); + TabOutputStr[OutputLength + 1] = L'\"'; + TabOutputStr[OutputLength + 2] = CHAR_NULL; + } else { + CopyMem (TabOutputStr, TabCurrent->FileName, OutputLength * sizeof (CHAR16)); + TabOutputStr[OutputLength] = CHAR_NULL; + } + OutputLength = StrLen (TabOutputStr) < MaxStr - 1 ? StrLen (TabOutputStr) : MaxStr - 1; + CopyMem (CurrentString + TabUpdatePos, TabOutputStr, OutputLength * sizeof (CHAR16)); + CurrentString[TabUpdatePos + OutputLength] = CHAR_NULL; + StringCurPos = TabUpdatePos + OutputLength; + Update = TabUpdatePos; + if (StringLen > TabUpdatePos + OutputLength) { + Delete = StringLen - TabUpdatePos - OutputLength; + } + + FreePool(TabOutputStr); + } + + // + // If we have a new position, we are preparing to print a previous or + // next command. + // + if (NewPos != (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory)) { + Column = StartColumn; + Row -= (StringCurPos + StartColumn) / TotalColumn; + + LinePos = NewPos; + NewPos = (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory); + + OutputLength = StrLen (LinePos->Buffer) < MaxStr - 1 ? StrLen (LinePos->Buffer) : MaxStr - 1; + CopyMem (CurrentString, LinePos->Buffer, OutputLength * sizeof (CHAR16)); + CurrentString[OutputLength] = CHAR_NULL; + + StringCurPos = OutputLength; + + // + // Draw new input string + // + Update = 0; + if (StringLen > OutputLength) { + // + // If old string was longer, blank its tail + // + Delete = StringLen - OutputLength; + } + } + // + // If we need to update the output do so now + // + if (Update != (UINTN) -1) { + ShellPrintEx ((INT32)Column, (INT32)Row, L"%s%.*s", CurrentString + Update, Delete, L""); + StringLen = StrLen (CurrentString); + + if (Delete != 0) { + SetMem (CurrentString + StringLen, Delete * sizeof (CHAR16), CHAR_NULL); + } + + if (StringCurPos > StringLen) { + StringCurPos = StringLen; + } + + Update = (UINTN) -1; + + // + // After using print to reflect newly updates, if we're not using + // BACKSPACE and DELETE, we need to move the cursor position forward, + // so adjust row and column here. + // + if (Key.UnicodeChar != CHAR_BACKSPACE && !(Key.UnicodeChar == 0 && Key.ScanCode == SCAN_DELETE)) { + // + // Calculate row and column of the tail of current string + // + TailRow = Row + (StringLen - StringCurPos + Column + OutputLength) / TotalColumn; + TailColumn = (StringLen - StringCurPos + Column + OutputLength) % TotalColumn; + + // + // If the tail of string reaches screen end, screen rolls up, so if + // Row does not equal TailRow, Row should be decremented + // + // (if we are recalling commands using UPPER and DOWN key, and if the + // old command is too long to fit the screen, TailColumn must be 79. + // + if (TailColumn == 0 && TailRow >= TotalRow && Row != TailRow) { + Row--; + } + // + // Calculate the cursor position after current operation. If cursor + // reaches line end, update both row and column, otherwise, only + // column will be changed. + // + if (Column + OutputLength >= TotalColumn) { + SkipLength = OutputLength - (TotalColumn - Column); + + Row += SkipLength / TotalColumn + 1; + if (Row > TotalRow - 1) { + Row = TotalRow - 1; + } + + Column = SkipLength % TotalColumn; + } else { + Column += OutputLength; + } + } + + Delete = 0; + } + // + // Set the cursor position for this key + // + gST->ConOut->SetCursorPosition (gST->ConOut, Column, Row); + } while (!Done); + + if (CurrentString != NULL && StrLen(CurrentString) > 0) { + // + // add the line to the history buffer + // + AddLineToCommandHistory(CurrentString); + } + + // + // Return the data to the caller + // + *BufferSize = StringLen * sizeof (CHAR16); + + // + // if this was used it should be deallocated by now... + // prevent memory leaks... + // + if (TabCompleteList != NULL) { + ShellInfoObject.NewEfiShellProtocol->FreeFileList (&TabCompleteList); + } + ASSERT(TabCompleteList == NULL); + + return Status; +} + +// +// FILE style interfaces for StdIn/StdOut/StdErr +// +EFI_FILE_PROTOCOL FileInterfaceStdIn = { + EFI_FILE_REVISION, + FileInterfaceOpenNotFound, + FileInterfaceNopGeneric, + FileInterfaceNopGeneric, + FileInterfaceStdInRead, + FileInterfaceStdInWrite, + FileInterfaceNopGetPosition, + FileInterfaceNopSetPosition, + FileInterfaceNopGetInfo, + FileInterfaceNopSetInfo, + FileInterfaceNopGeneric +}; + +EFI_FILE_PROTOCOL FileInterfaceStdOut = { + EFI_FILE_REVISION, + FileInterfaceOpenNotFound, + FileInterfaceNopGeneric, + FileInterfaceNopGeneric, + FileInterfaceStdOutRead, + FileInterfaceStdOutWrite, + FileInterfaceNopGetPosition, + FileInterfaceNopSetPosition, + FileInterfaceNopGetInfo, + FileInterfaceNopSetInfo, + FileInterfaceNopGeneric +}; + +EFI_FILE_PROTOCOL FileInterfaceStdErr = { + EFI_FILE_REVISION, + FileInterfaceOpenNotFound, + FileInterfaceNopGeneric, + FileInterfaceNopGeneric, + FileInterfaceStdErrRead, + FileInterfaceStdErrWrite, + FileInterfaceNopGetPosition, + FileInterfaceNopSetPosition, + FileInterfaceNopGetInfo, + FileInterfaceNopSetInfo, + FileInterfaceNopGeneric +}; + +EFI_FILE_PROTOCOL FileInterfaceNulFile = { + EFI_FILE_REVISION, + FileInterfaceOpenNotFound, + FileInterfaceNopGeneric, + FileInterfaceNopGeneric, + FileInterfaceNulRead, + FileInterfaceNulWrite, + FileInterfaceNopGetPosition, + FileInterfaceNopSetPosition, + FileInterfaceNopGetInfo, + FileInterfaceNopSetInfo, + FileInterfaceNopGeneric +}; + + + + +// +// This is identical to EFI_FILE_PROTOCOL except for the additional member +// for the name. +// + +typedef struct { + UINT64 Revision; + EFI_FILE_OPEN Open; + EFI_FILE_CLOSE Close; + EFI_FILE_DELETE Delete; + EFI_FILE_READ Read; + EFI_FILE_WRITE Write; + EFI_FILE_GET_POSITION GetPosition; + EFI_FILE_SET_POSITION SetPosition; + EFI_FILE_GET_INFO GetInfo; + EFI_FILE_SET_INFO SetInfo; + EFI_FILE_FLUSH Flush; + CHAR16 Name[1]; +} EFI_FILE_PROTOCOL_ENVIRONMENT; +//ANSI compliance helper to get size of the struct. +#define SIZE_OF_EFI_FILE_PROTOCOL_ENVIRONMENT EFI_FIELD_OFFSET (EFI_FILE_PROTOCOL_ENVIRONMENT, Name) + +/** + File style interface for Environment Variable (Close). + + Frees the memory for this object. + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + + @retval EFI_SUCCESS +**/ +EFI_STATUS +EFIAPI +FileInterfaceEnvClose( + IN EFI_FILE_PROTOCOL *This + ) +{ + VOID* NewBuffer; + UINTN NewSize; + EFI_STATUS Status; + BOOLEAN Volatile; + UINTN TotalSize; + + // + // Most if not all UEFI commands will have an '\r\n' at the end of any output. + // Since the output was redirected to a variable, it does not make sense to + // keep this. So, before closing, strip the trailing '\r\n' from the variable + // if it exists. + // + NewBuffer = NULL; + NewSize = 0; + TotalSize = 0; + + Status = IsVolatileEnv (((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &Volatile); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + TotalSize = NewSize + sizeof (CHAR16); + NewBuffer = AllocateZeroPool (TotalSize); + if (NewBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer); + } + + if (!EFI_ERROR(Status) && NewBuffer != NULL) { + + if (TotalSize / sizeof (CHAR16) >= 3) { + if ( (((CHAR16*)NewBuffer)[TotalSize / sizeof (CHAR16) - 2] == CHAR_LINEFEED) && + (((CHAR16*)NewBuffer)[TotalSize / sizeof (CHAR16) - 3] == CHAR_CARRIAGE_RETURN) + ) { + ((CHAR16*)NewBuffer)[TotalSize / sizeof (CHAR16) - 3] = CHAR_NULL; + // + // If the NewBuffer end with \r\n\0, We will replace '\r' by '\0' and then update TotalSize. + // + TotalSize -= sizeof(CHAR16) * 2; + } + + if (Volatile) { + Status = SHELL_SET_ENVIRONMENT_VARIABLE_V ( + ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, + TotalSize - sizeof (CHAR16), + NewBuffer + ); + + if (!EFI_ERROR(Status)) { + Status = ShellAddEnvVarToList ( + ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, + NewBuffer, + TotalSize, + EFI_VARIABLE_BOOTSERVICE_ACCESS + ); + } + } else { + Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV ( + ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, + TotalSize - sizeof (CHAR16), + NewBuffer + ); + + if (!EFI_ERROR(Status)) { + Status = ShellAddEnvVarToList ( + ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, + NewBuffer, + TotalSize, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS + ); + } + } + } + } + + SHELL_FREE_NON_NULL(NewBuffer); + FreePool((EFI_FILE_PROTOCOL_ENVIRONMENT*)This); + return (Status); +} + +/** + File style interface for Environment Variable (Delete). + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + + @retval The return value from FileInterfaceEnvClose(). +**/ +EFI_STATUS +EFIAPI +FileInterfaceEnvDelete( + IN EFI_FILE_PROTOCOL *This + ) +{ + SHELL_DELETE_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name); + return (FileInterfaceEnvClose(This)); +} + +/** + File style interface for Environment Variable (Read). + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + @param[in, out] BufferSize Size in bytes of Buffer. + @param[out] Buffer The pointer to the buffer to fill. + + @retval EFI_SUCCESS The data was read. +**/ +EFI_STATUS +EFIAPI +FileInterfaceEnvRead( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + + *BufferSize = *BufferSize / sizeof (CHAR16) * sizeof (CHAR16); + if (*BufferSize != 0) { + // + // Make sure the first unicode character is \xFEFF + // + *(CHAR16 *)Buffer = gUnicodeFileTag; + Buffer = (CHAR16 *)Buffer + 1; + *BufferSize -= sizeof (gUnicodeFileTag); + } + + Status = SHELL_GET_ENVIRONMENT_VARIABLE ( + ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, + BufferSize, + Buffer + ); + if (!EFI_ERROR (Status) || (Status == EFI_BUFFER_TOO_SMALL)) { + // + // BufferSize is valid and needs update when Status is Success or BufferTooSmall. + // + *BufferSize += sizeof (gUnicodeFileTag); + } + return Status; +} + +/** + File style interface for Volatile Environment Variable (Write). + This function also caches the environment variable into gShellEnvVarList. + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + @param[in, out] BufferSize Size in bytes of Buffer. + @param[in] Buffer The pointer to the buffer to write. + + @retval EFI_SUCCESS The data was successfully write to variable. + @retval SHELL_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +EFIAPI +FileInterfaceEnvVolWrite( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + VOID* NewBuffer; + UINTN NewSize; + EFI_STATUS Status; + UINTN TotalSize; + + NewBuffer = NULL; + NewSize = 0; + TotalSize = 0; + + Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + TotalSize = NewSize + *BufferSize + sizeof (CHAR16); + } else if (Status == EFI_NOT_FOUND) { + TotalSize = *BufferSize + sizeof(CHAR16); + } else { + return Status; + } + + NewBuffer = AllocateZeroPool (TotalSize); + if (NewBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (Status == EFI_BUFFER_TOO_SMALL) { + Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer); + } + + if (EFI_ERROR (Status) && Status != EFI_NOT_FOUND) { + FreePool (NewBuffer); + return Status; + } + + CopyMem ((UINT8*)NewBuffer + NewSize, Buffer, *BufferSize); + Status = ShellAddEnvVarToList ( + ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, + NewBuffer, + TotalSize, + EFI_VARIABLE_BOOTSERVICE_ACCESS + ); + if (EFI_ERROR(Status)) { + FreePool (NewBuffer); + return Status; + } + + Status = SHELL_SET_ENVIRONMENT_VARIABLE_V ( + ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, + TotalSize - sizeof (CHAR16), + NewBuffer + ); + if (EFI_ERROR(Status)) { + ShellRemvoeEnvVarFromList (((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name); + } + + FreePool (NewBuffer); + return Status; +} + + +/** + File style interface for Non Volatile Environment Variable (Write). + This function also caches the environment variable into gShellEnvVarList. + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + @param[in, out] BufferSize Size in bytes of Buffer. + @param[in] Buffer The pointer to the buffer to write. + + @retval EFI_SUCCESS The data was successfully write to variable. + @retval SHELL_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +EFIAPI +FileInterfaceEnvNonVolWrite( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + VOID* NewBuffer; + UINTN NewSize; + EFI_STATUS Status; + UINTN TotalSize; + + NewBuffer = NULL; + NewSize = 0; + TotalSize = 0; + + Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + TotalSize = NewSize + *BufferSize + sizeof (CHAR16); + } else if (Status == EFI_NOT_FOUND) { + TotalSize = *BufferSize + sizeof (CHAR16); + } else { + return Status; + } + + NewBuffer = AllocateZeroPool (TotalSize); + if (NewBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (Status == EFI_BUFFER_TOO_SMALL) { + Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer); + } + + if (EFI_ERROR(Status) && Status != EFI_NOT_FOUND) { + FreePool (NewBuffer); + return Status; + } + + CopyMem ((UINT8*) NewBuffer + NewSize, Buffer, *BufferSize); + Status = ShellAddEnvVarToList ( + ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, + NewBuffer, + TotalSize, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS + ); + if (EFI_ERROR (Status)) { + FreePool (NewBuffer); + return Status; + } + + Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV ( + ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, + TotalSize - sizeof (CHAR16), + NewBuffer + ); + if (EFI_ERROR (Status)) { + ShellRemvoeEnvVarFromList (((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name); + } + + FreePool (NewBuffer); + return Status; +} + +/** + Creates a EFI_FILE_PROTOCOL (almost) object for using to access + environment variables through file operations. + + @param EnvName The name of the Environment Variable to be operated on. + + @retval NULL Memory could not be allocated. + @return other a pointer to an EFI_FILE_PROTOCOL structure +**/ +EFI_FILE_PROTOCOL* +CreateFileInterfaceEnv( + IN CONST CHAR16 *EnvName + ) +{ + EFI_STATUS Status; + EFI_FILE_PROTOCOL_ENVIRONMENT *EnvFileInterface; + UINTN EnvNameSize; + BOOLEAN Volatile; + + if (EnvName == NULL) { + return (NULL); + } + + Status = IsVolatileEnv (EnvName, &Volatile); + if (EFI_ERROR (Status)) { + return NULL; + } + + // + // Get some memory + // + EnvNameSize = StrSize(EnvName); + EnvFileInterface = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_ENVIRONMENT)+EnvNameSize); + if (EnvFileInterface == NULL){ + return (NULL); + } + + // + // Assign the generic members + // + EnvFileInterface->Revision = EFI_FILE_REVISION; + EnvFileInterface->Open = FileInterfaceOpenNotFound; + EnvFileInterface->Close = FileInterfaceEnvClose; + EnvFileInterface->GetPosition = FileInterfaceNopGetPosition; + EnvFileInterface->SetPosition = FileInterfaceNopSetPosition; + EnvFileInterface->GetInfo = FileInterfaceNopGetInfo; + EnvFileInterface->SetInfo = FileInterfaceNopSetInfo; + EnvFileInterface->Flush = FileInterfaceNopGeneric; + EnvFileInterface->Delete = FileInterfaceEnvDelete; + EnvFileInterface->Read = FileInterfaceEnvRead; + + CopyMem(EnvFileInterface->Name, EnvName, EnvNameSize); + + // + // Assign the different members for Volatile and Non-Volatile variables + // + if (Volatile) { + EnvFileInterface->Write = FileInterfaceEnvVolWrite; + } else { + EnvFileInterface->Write = FileInterfaceEnvNonVolWrite; + } + return ((EFI_FILE_PROTOCOL *)EnvFileInterface); +} + +/** + Move the cursor position one character backward. + + @param[in] LineLength Length of a line. Get it by calling QueryMode + @param[in, out] Column Current column of the cursor position + @param[in, out] Row Current row of the cursor position +**/ +VOID +MoveCursorBackward ( + IN UINTN LineLength, + IN OUT UINTN *Column, + IN OUT UINTN *Row + ) +{ + // + // If current column is 0, move to the last column of the previous line, + // otherwise, just decrement column. + // + if (*Column == 0) { + *Column = LineLength - 1; + if (*Row > 0) { + (*Row)--; + } + return; + } + (*Column)--; +} + +/** + Move the cursor position one character forward. + + @param[in] LineLength Length of a line. + @param[in] TotalRow Total row of a screen + @param[in, out] Column Current column of the cursor position + @param[in, out] Row Current row of the cursor position +**/ +VOID +MoveCursorForward ( + IN UINTN LineLength, + IN UINTN TotalRow, + IN OUT UINTN *Column, + IN OUT UINTN *Row + ) +{ + // + // Increment Column. + // If this puts column past the end of the line, move to first column + // of the next row. + // + (*Column)++; + if (*Column >= LineLength) { + (*Column) = 0; + if ((*Row) < TotalRow - 1) { + (*Row)++; + } + } +} + +/** + Prints out each previously typed command in the command list history log. + + When each screen is full it will pause for a key before continuing. + + @param[in] TotalCols How many columns are on the screen + @param[in] TotalRows How many rows are on the screen + @param[in] StartColumn which column to start at +**/ +VOID +PrintCommandHistory ( + IN CONST UINTN TotalCols, + IN CONST UINTN TotalRows, + IN CONST UINTN StartColumn + ) +{ + BUFFER_LIST *Node; + UINTN Index; + UINTN LineNumber; + UINTN LineCount; + + ShellPrintEx (-1, -1, L"\n"); + Index = 0; + LineNumber = 0; + // + // go through history list... + // + for ( Node = (BUFFER_LIST*)GetFirstNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link) + ; !IsNull(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link) + ; Node = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link) + ){ + Index++; + LineCount = ((StrLen (Node->Buffer) + StartColumn + 1) / TotalCols) + 1; + + if (LineNumber + LineCount >= TotalRows) { + ShellPromptForResponseHii( + ShellPromptResponseTypeEnterContinue, + STRING_TOKEN (STR_SHELL_ENTER_TO_CONT), + ShellInfoObject.HiiHandle, + NULL + ); + LineNumber = 0; + } + ShellPrintEx (-1, -1, L"%2d. %s\n", Index, Node->Buffer); + LineNumber += LineCount; + } +} + + + + + + +// +// This is identical to EFI_FILE_PROTOCOL except for the additional members +// for the buffer, size, and position. +// + +typedef struct { + UINT64 Revision; + EFI_FILE_OPEN Open; + EFI_FILE_CLOSE Close; + EFI_FILE_DELETE Delete; + EFI_FILE_READ Read; + EFI_FILE_WRITE Write; + EFI_FILE_GET_POSITION GetPosition; + EFI_FILE_SET_POSITION SetPosition; + EFI_FILE_GET_INFO GetInfo; + EFI_FILE_SET_INFO SetInfo; + EFI_FILE_FLUSH Flush; + VOID *Buffer; + UINT64 Position; + UINT64 BufferSize; + BOOLEAN Unicode; + UINT64 FileSize; +} EFI_FILE_PROTOCOL_MEM; + +/** + File style interface for Mem (SetPosition). + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + @param[out] Position The position to set. + + @retval EFI_SUCCESS The position was successfully changed. + @retval EFI_INVALID_PARAMETER The Position was invalid. +**/ +EFI_STATUS +EFIAPI +FileInterfaceMemSetPosition( + IN EFI_FILE_PROTOCOL *This, + OUT UINT64 Position + ) +{ + if (Position <= ((EFI_FILE_PROTOCOL_MEM*)This)->FileSize) { + ((EFI_FILE_PROTOCOL_MEM*)This)->Position = Position; + return (EFI_SUCCESS); + } else { + return (EFI_INVALID_PARAMETER); + } +} + +/** + File style interface for Mem (GetPosition). + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + @param[out] Position The pointer to the position. + + @retval EFI_SUCCESS The position was retrieved. +**/ +EFI_STATUS +EFIAPI +FileInterfaceMemGetPosition( + IN EFI_FILE_PROTOCOL *This, + OUT UINT64 *Position + ) +{ + *Position = ((EFI_FILE_PROTOCOL_MEM*)This)->Position; + return (EFI_SUCCESS); +} + +/** + File style interface for Mem (GetInfo). + + @param This Protocol instance pointer. + @param InformationType Type of information to return in Buffer. + @param BufferSize On input size of buffer, on output amount of data in buffer. + @param Buffer The buffer to return data. + + @retval EFI_SUCCESS Data was returned. + @retval EFI_UNSUPPORT InformationType is not supported. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The device is write protected. + @retval EFI_ACCESS_DENIED The file was open for read only. + @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize. + +**/ +EFI_STATUS +EFIAPI +FileInterfaceMemGetInfo( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + EFI_FILE_INFO *FileInfo; + + if (CompareGuid (InformationType, &gEfiFileInfoGuid)) { + if (*BufferSize < sizeof (EFI_FILE_INFO)) { + *BufferSize = sizeof (EFI_FILE_INFO); + return EFI_BUFFER_TOO_SMALL; + } + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + FileInfo = (EFI_FILE_INFO *)Buffer; + FileInfo->Size = sizeof (*FileInfo); + ZeroMem (FileInfo, sizeof (*FileInfo)); + FileInfo->FileSize = ((EFI_FILE_PROTOCOL_MEM*)This)->FileSize; + FileInfo->PhysicalSize = FileInfo->FileSize; + return EFI_SUCCESS; + } + + return EFI_UNSUPPORTED; +} + +/** + File style interface for Mem (Write). + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + @param[in, out] BufferSize Size in bytes of Buffer. + @param[in] Buffer The pointer to the buffer to write. + + @retval EFI_OUT_OF_RESOURCES The operation failed due to lack of resources. + @retval EFI_SUCCESS The data was written. +**/ +EFI_STATUS +EFIAPI +FileInterfaceMemWrite( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + CHAR8 *AsciiBuffer; + EFI_FILE_PROTOCOL_MEM *MemFile; + + MemFile = (EFI_FILE_PROTOCOL_MEM *) This; + if (MemFile->Unicode) { + // + // Unicode + // + if ((UINTN)(MemFile->Position + (*BufferSize)) > (UINTN)(MemFile->BufferSize)) { + MemFile->Buffer = ReallocatePool((UINTN)(MemFile->BufferSize), (UINTN)(MemFile->BufferSize) + (*BufferSize) + MEM_WRITE_REALLOC_OVERHEAD, MemFile->Buffer); + if (MemFile->Buffer == NULL){ + return EFI_OUT_OF_RESOURCES; + } + MemFile->BufferSize += (*BufferSize) + MEM_WRITE_REALLOC_OVERHEAD; + } + CopyMem(((UINT8*)MemFile->Buffer) + MemFile->Position, Buffer, *BufferSize); + MemFile->Position += (*BufferSize); + MemFile->FileSize = MemFile->Position; + return (EFI_SUCCESS); + } else { + // + // Ascii + // + AsciiBuffer = AllocateZeroPool(*BufferSize); + if (AsciiBuffer == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + AsciiSPrint(AsciiBuffer, *BufferSize, "%S", Buffer); + if ((UINTN)(MemFile->Position + AsciiStrSize(AsciiBuffer)) > (UINTN)(MemFile->BufferSize)) { + MemFile->Buffer = ReallocatePool((UINTN)(MemFile->BufferSize), (UINTN)(MemFile->BufferSize) + AsciiStrSize(AsciiBuffer) + MEM_WRITE_REALLOC_OVERHEAD, MemFile->Buffer); + if (MemFile->Buffer == NULL){ + FreePool(AsciiBuffer); + return EFI_OUT_OF_RESOURCES; + } + MemFile->BufferSize += AsciiStrSize(AsciiBuffer) + MEM_WRITE_REALLOC_OVERHEAD; + } + CopyMem(((UINT8*)MemFile->Buffer) + MemFile->Position, AsciiBuffer, AsciiStrSize(AsciiBuffer)); + MemFile->Position += (*BufferSize / sizeof(CHAR16)); + MemFile->FileSize = MemFile->Position; + FreePool(AsciiBuffer); + return (EFI_SUCCESS); + } +} + +/** + File style interface for Mem (Read). + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + @param[in, out] BufferSize Size in bytes of Buffer. + @param[in] Buffer The pointer to the buffer to fill. + + @retval EFI_SUCCESS The data was read. +**/ +EFI_STATUS +EFIAPI +FileInterfaceMemRead( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + EFI_FILE_PROTOCOL_MEM *MemFile; + + MemFile = (EFI_FILE_PROTOCOL_MEM *) This; + if (*BufferSize > (UINTN)((MemFile->FileSize) - (UINTN)(MemFile->Position))) { + (*BufferSize) = (UINTN)((MemFile->FileSize) - (UINTN)(MemFile->Position)); + } + CopyMem(Buffer, ((UINT8*)MemFile->Buffer) + MemFile->Position, (*BufferSize)); + MemFile->Position = MemFile->Position + (*BufferSize); + return (EFI_SUCCESS); +} + +/** + File style interface for Mem (Close). + + Frees all memory associated with this object. + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + + @retval EFI_SUCCESS The 'file' was closed. +**/ +EFI_STATUS +EFIAPI +FileInterfaceMemClose( + IN EFI_FILE_PROTOCOL *This + ) +{ + SHELL_FREE_NON_NULL(((EFI_FILE_PROTOCOL_MEM*)This)->Buffer); + SHELL_FREE_NON_NULL(This); + return (EFI_SUCCESS); +} + +/** + Creates a EFI_FILE_PROTOCOL (almost) object for using to access + a file entirely in memory through file operations. + + @param[in] Unicode Boolean value with TRUE for Unicode and FALSE for Ascii. + + @retval NULL Memory could not be allocated. + @return other A pointer to an EFI_FILE_PROTOCOL structure. +**/ +EFI_FILE_PROTOCOL* +CreateFileInterfaceMem( + IN CONST BOOLEAN Unicode + ) +{ + EFI_FILE_PROTOCOL_MEM *FileInterface; + + // + // Get some memory + // + FileInterface = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_MEM)); + if (FileInterface == NULL){ + return (NULL); + } + + // + // Assign the generic members + // + FileInterface->Revision = EFI_FILE_REVISION; + FileInterface->Open = FileInterfaceOpenNotFound; + FileInterface->Close = FileInterfaceMemClose; + FileInterface->GetPosition = FileInterfaceMemGetPosition; + FileInterface->SetPosition = FileInterfaceMemSetPosition; + FileInterface->GetInfo = FileInterfaceMemGetInfo; + FileInterface->SetInfo = FileInterfaceNopSetInfo; + FileInterface->Flush = FileInterfaceNopGeneric; + FileInterface->Delete = FileInterfaceNopGeneric; + FileInterface->Read = FileInterfaceMemRead; + FileInterface->Write = FileInterfaceMemWrite; + FileInterface->Unicode = Unicode; + + ASSERT(FileInterface->Buffer == NULL); + ASSERT(FileInterface->BufferSize == 0); + ASSERT(FileInterface->Position == 0); + + if (Unicode) { + FileInterface->Buffer = AllocateZeroPool(sizeof(gUnicodeFileTag)); + if (FileInterface->Buffer == NULL) { + FreePool (FileInterface); + return NULL; + } + *((CHAR16 *) (FileInterface->Buffer)) = EFI_UNICODE_BYTE_ORDER_MARK; + FileInterface->BufferSize = 2; + FileInterface->Position = 2; + } + + return ((EFI_FILE_PROTOCOL *)FileInterface); +} + +typedef struct { + UINT64 Revision; + EFI_FILE_OPEN Open; + EFI_FILE_CLOSE Close; + EFI_FILE_DELETE Delete; + EFI_FILE_READ Read; + EFI_FILE_WRITE Write; + EFI_FILE_GET_POSITION GetPosition; + EFI_FILE_SET_POSITION SetPosition; + EFI_FILE_GET_INFO GetInfo; + EFI_FILE_SET_INFO SetInfo; + EFI_FILE_FLUSH Flush; + BOOLEAN Unicode; + EFI_FILE_PROTOCOL *Orig; +} EFI_FILE_PROTOCOL_FILE; + +/** + Set a files current position + + @param This Protocol instance pointer. + @param Position Byte position from the start of the file. + + @retval EFI_SUCCESS Data was written. + @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open. + +**/ +EFI_STATUS +EFIAPI +FileInterfaceFileSetPosition( + IN EFI_FILE_PROTOCOL *This, + IN UINT64 Position + ) +{ + return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->SetPosition(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, Position); +} + +/** + Get a file's current position + + @param This Protocol instance pointer. + @param Position Byte position from the start of the file. + + @retval EFI_SUCCESS Data was written. + @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.. + +**/ +EFI_STATUS +EFIAPI +FileInterfaceFileGetPosition( + IN EFI_FILE_PROTOCOL *This, + OUT UINT64 *Position + ) +{ + return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->GetPosition(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, Position); +} + +/** + Get information about a file. + + @param This Protocol instance pointer. + @param InformationType Type of information to return in Buffer. + @param BufferSize On input size of buffer, on output amount of data in buffer. + @param Buffer The buffer to return data. + + @retval EFI_SUCCESS Data was returned. + @retval EFI_UNSUPPORT InformationType is not supported. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The device is write protected. + @retval EFI_ACCESS_DENIED The file was open for read only. + @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize. + +**/ +EFI_STATUS +EFIAPI +FileInterfaceFileGetInfo( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->GetInfo(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, InformationType, BufferSize, Buffer); +} + +/** + Set information about a file + + @param This Protocol instance pointer. + @param InformationType Type of information in Buffer. + @param BufferSize Size of buffer. + @param Buffer The data to write. + + @retval EFI_SUCCESS Data was returned. + @retval EFI_UNSUPPORT InformationType is not supported. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The device is write protected. + @retval EFI_ACCESS_DENIED The file was open for read only. + +**/ +EFI_STATUS +EFIAPI +FileInterfaceFileSetInfo( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->SetInfo(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, InformationType, BufferSize, Buffer); +} + +/** + Flush data back for the file handle. + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS Data was written. + @retval EFI_UNSUPPORT Writes to Open directory are not supported. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The device is write protected. + @retval EFI_ACCESS_DENIED The file was open for read only. + @retval EFI_VOLUME_FULL The volume is full. + +**/ +EFI_STATUS +EFIAPI +FileInterfaceFileFlush( + IN EFI_FILE_PROTOCOL *This + ) +{ + return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Flush(((EFI_FILE_PROTOCOL_FILE*)This)->Orig); +} + +/** + Read data from the file. + + @param This Protocol instance pointer. + @param BufferSize On input size of buffer, on output amount of data in buffer. + @param Buffer The buffer in which data is read. + + @retval EFI_SUCCESS Data was read. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains required size. + +**/ +EFI_STATUS +EFIAPI +FileInterfaceFileRead( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINT64 Position; + CHAR8 *AsciiStrBuffer; + CHAR16 *UscStrBuffer; + UINTN Size; + if (((EFI_FILE_PROTOCOL_FILE*)This)->Unicode) { + // + // Unicode + // There might be different file tag for the Unicode file. We cannot unconditionally insert the \xFEFF. + // So we choose to leave the file content as is. + // + return (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Read(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, BufferSize, Buffer)); + } else { + // + // Ascii + // + *BufferSize = *BufferSize / sizeof (CHAR16) * sizeof (CHAR16); + if (*BufferSize == 0) { + return EFI_SUCCESS; + } + Status = ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->GetPosition (((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Position); + if (EFI_ERROR (Status)) { + return Status; + } + if (Position == 0) { + // + // First two bytes in Buffer is for the Unicode file tag. + // + *(CHAR16 *)Buffer = gUnicodeFileTag; + Buffer = (CHAR16 *)Buffer + 1; + Size = *BufferSize / sizeof (CHAR16) - 1; + } else { + Size = *BufferSize / sizeof (CHAR16); + } + AsciiStrBuffer = AllocateZeroPool (Size + 1); + if (AsciiStrBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + UscStrBuffer = AllocateZeroPool ((Size + 1) * sizeof(CHAR16)); + if (UscStrBuffer== NULL) { + SHELL_FREE_NON_NULL(AsciiStrBuffer); + return EFI_OUT_OF_RESOURCES; + } + Status = ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Read (((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiStrBuffer); + if (!EFI_ERROR(Status)) { + AsciiStrToUnicodeStrS (AsciiStrBuffer, UscStrBuffer, Size + 1); + *BufferSize = Size * sizeof (CHAR16); + CopyMem (Buffer, UscStrBuffer, *BufferSize); + } + SHELL_FREE_NON_NULL (AsciiStrBuffer); + SHELL_FREE_NON_NULL (UscStrBuffer); + return Status; + } +} + +/** + Opens a new file relative to the source file's location. + + @param[in] This The protocol instance pointer. + @param[out] NewHandle Returns File Handle for FileName. + @param[in] FileName Null terminated string. "\", ".", and ".." are supported. + @param[in] OpenMode Open mode for file. + @param[in] Attributes Only used for EFI_FILE_MODE_CREATE. + + @retval EFI_SUCCESS The device was opened. + @retval EFI_NOT_FOUND The specified file could not be found on the device. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_MEDIA_CHANGED The media has changed. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_ACCESS_DENIED The service denied access to the file. + @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources. + @retval EFI_VOLUME_FULL The volume is full. +**/ +EFI_STATUS +EFIAPI +FileInterfaceFileOpen ( + IN EFI_FILE_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes + ) +{ + return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Open(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, NewHandle, FileName, OpenMode, Attributes); +} + +/** + Close and delete the file handle. + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS The device was opened. + @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted. + +**/ +EFI_STATUS +EFIAPI +FileInterfaceFileDelete( + IN EFI_FILE_PROTOCOL *This + ) +{ + EFI_STATUS Status; + Status = ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Delete(((EFI_FILE_PROTOCOL_FILE*)This)->Orig); + FreePool(This); + return (Status); +} + +/** + File style interface for File (Close). + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + + @retval EFI_SUCCESS The file was closed. +**/ +EFI_STATUS +EFIAPI +FileInterfaceFileClose( + IN EFI_FILE_PROTOCOL *This + ) +{ + EFI_STATUS Status; + Status = ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Close(((EFI_FILE_PROTOCOL_FILE*)This)->Orig); + FreePool(This); + return (Status); +} + +/** + File style interface for File (Write). + + If the file was opened with ASCII mode the data will be processed through + AsciiSPrint before writing. + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + @param[in, out] BufferSize Size in bytes of Buffer. + @param[in] Buffer The pointer to the buffer to write. + + @retval EFI_SUCCESS The data was written. +**/ +EFI_STATUS +EFIAPI +FileInterfaceFileWrite( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + CHAR8 *AsciiBuffer; + UINTN Size; + EFI_STATUS Status; + if (((EFI_FILE_PROTOCOL_FILE*)This)->Unicode) { + // + // Unicode + // + return (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Write(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, BufferSize, Buffer)); + } else { + // + // Ascii + // + AsciiBuffer = AllocateZeroPool(*BufferSize); + AsciiSPrint(AsciiBuffer, *BufferSize, "%S", Buffer); + Size = AsciiStrSize(AsciiBuffer) - 1; // (we dont need the null terminator) + Status = (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Write(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiBuffer)); + FreePool(AsciiBuffer); + return (Status); + } +} + +/** + Create a file interface with unicode information. + + This will create a new EFI_FILE_PROTOCOL identical to the Templace + except that the new one has Unicode and Ascii knowledge. + + @param[in] Template A pointer to the EFI_FILE_PROTOCOL object. + @param[in] Unicode TRUE for UCS-2, FALSE for ASCII. + + @return a new EFI_FILE_PROTOCOL object to be used instead of the template. +**/ +EFI_FILE_PROTOCOL* +CreateFileInterfaceFile( + IN CONST EFI_FILE_PROTOCOL *Template, + IN CONST BOOLEAN Unicode + ) +{ + EFI_FILE_PROTOCOL_FILE *NewOne; + + NewOne = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_FILE)); + if (NewOne == NULL) { + return (NULL); + } + CopyMem(NewOne, Template, sizeof(EFI_FILE_PROTOCOL_FILE)); + NewOne->Orig = (EFI_FILE_PROTOCOL *)Template; + NewOne->Unicode = Unicode; + NewOne->Open = FileInterfaceFileOpen; + NewOne->Close = FileInterfaceFileClose; + NewOne->Delete = FileInterfaceFileDelete; + NewOne->Read = FileInterfaceFileRead; + NewOne->Write = FileInterfaceFileWrite; + NewOne->GetPosition = FileInterfaceFileGetPosition; + NewOne->SetPosition = FileInterfaceFileSetPosition; + NewOne->GetInfo = FileInterfaceFileGetInfo; + NewOne->SetInfo = FileInterfaceFileSetInfo; + NewOne->Flush = FileInterfaceFileFlush; + + return ((EFI_FILE_PROTOCOL *)NewOne); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/FileHandleWrappers.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/FileHandleWrappers.h new file mode 100644 index 00000000..0e293a9d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/FileHandleWrappers.h @@ -0,0 +1,87 @@ +/** @file + EFI_FILE_PROTOCOL wrappers for other items (Like Environment Variables, StdIn, StdOut, StdErr, etc...) + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SHELL_FILE_HANDLE_WRAPPERS_HEADER_ +#define _SHELL_FILE_HANDLE_WRAPPERS_HEADER_ + +typedef struct { + LIST_ENTRY Link; + CHAR16* Buffer; +} SHELL_LINE_LIST; + +typedef struct { + UINTN LogCount; + SHELL_LINE_LIST *Log; +} SHELL_LINE_LOG; + +/// +/// FILE styte interfaces for StdIn. +/// +extern EFI_FILE_PROTOCOL FileInterfaceStdIn; + +/// +/// FILE styte interfaces for StdOut. +/// +extern EFI_FILE_PROTOCOL FileInterfaceStdOut; + +/// +/// FILE styte interfaces for StdErr. +/// +extern EFI_FILE_PROTOCOL FileInterfaceStdErr; + +/// +/// FILE style interface for NUL file. +/// +extern EFI_FILE_PROTOCOL FileInterfaceNulFile; + +/** + Creates a EFI_FILE_PROTOCOL (almost) object for using to access + environment variables through file operations. + + @param EnvName The name of the Environment Variable to be operated on. + + @retval NULL Memory could not be allocated. + @return other a pointer to an EFI_FILE_PROTOCOL structure +**/ +EFI_FILE_PROTOCOL* +CreateFileInterfaceEnv( + CONST CHAR16 *EnvName + ); + +/** + Creates a EFI_FILE_PROTOCOL (almost) object for using to access + a file entirely in memory through file operations. + + @param[in] Unicode TRUE if the data is UNICODE, FALSE otherwise. + + @retval NULL Memory could not be allocated. + @return other a pointer to an EFI_FILE_PROTOCOL structure +**/ +EFI_FILE_PROTOCOL* +CreateFileInterfaceMem( + IN CONST BOOLEAN Unicode + ); + +/** + Creates a EFI_FILE_PROTOCOL (almost) object for using to access + a file entirely with unicode awareness through file operations. + + @param[in] Template The pointer to the handle to start with. + @param[in] Unicode TRUE if the data is UNICODE, FALSE otherwise. + + @retval NULL Memory could not be allocated. + @return other a pointer to an EFI_FILE_PROTOCOL structure +**/ +EFI_FILE_PROTOCOL* +CreateFileInterfaceFile( + IN CONST EFI_FILE_PROTOCOL *Template, + IN CONST BOOLEAN Unicode + ); + +#endif //_SHELL_FILE_HANDLE_WRAPPERS_HEADER_ + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/Shell.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/Shell.c new file mode 100644 index 00000000..99b2194c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/Shell.c @@ -0,0 +1,3183 @@ +/** @file + This is THE shell (application) + + Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.
+ (C) Copyright 2013-2014 Hewlett-Packard Development Company, L.P.
+ Copyright 2015-2018 Dell Technologies.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Shell.h" + +// +// Initialize the global structure +// +SHELL_INFO ShellInfoObject = { + NULL, + NULL, + FALSE, + FALSE, + { + {{ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + }}, + 0, + NULL, + NULL + }, + {{NULL, NULL}, NULL}, + { + {{NULL, NULL}, NULL}, + 0, + 0, + TRUE + }, + NULL, + 0, + NULL, + NULL, + NULL, + NULL, + NULL, + {{NULL, NULL}, NULL, NULL}, + {{NULL, NULL}, NULL, NULL}, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + FALSE +}; + +STATIC CONST CHAR16 mScriptExtension[] = L".NSH"; +STATIC CONST CHAR16 mExecutableExtensions[] = L".NSH;.EFI"; +STATIC CONST CHAR16 mStartupScript[] = L"startup.nsh"; +CONST CHAR16 mNoNestingEnvVarName[] = L"nonesting"; +CONST CHAR16 mNoNestingTrue[] = L"True"; +CONST CHAR16 mNoNestingFalse[] = L"False"; + +/** + Cleans off leading and trailing spaces and tabs. + + @param[in] String pointer to the string to trim them off. +**/ +EFI_STATUS +TrimSpaces( + IN CHAR16 **String + ) +{ + ASSERT(String != NULL); + ASSERT(*String!= NULL); + // + // Remove any spaces and tabs at the beginning of the (*String). + // + while (((*String)[0] == L' ') || ((*String)[0] == L'\t')) { + CopyMem((*String), (*String)+1, StrSize((*String)) - sizeof((*String)[0])); + } + + // + // Remove any spaces and tabs at the end of the (*String). + // + while ((StrLen (*String) > 0) && (((*String)[StrLen((*String))-1] == L' ') || ((*String)[StrLen((*String))-1] == L'\t'))) { + (*String)[StrLen((*String))-1] = CHAR_NULL; + } + + return (EFI_SUCCESS); +} + +/** + Parse for the next instance of one string within another string. Can optionally make sure that + the string was not escaped (^ character) per the shell specification. + + @param[in] SourceString The string to search within + @param[in] FindString The string to look for + @param[in] CheckForEscapeCharacter TRUE to skip escaped instances of FinfString, otherwise will return even escaped instances +**/ +CHAR16* +FindNextInstance( + IN CONST CHAR16 *SourceString, + IN CONST CHAR16 *FindString, + IN CONST BOOLEAN CheckForEscapeCharacter + ) +{ + CHAR16 *Temp; + if (SourceString == NULL) { + return (NULL); + } + Temp = StrStr(SourceString, FindString); + + // + // If nothing found, or we don't care about escape characters + // + if (Temp == NULL || !CheckForEscapeCharacter) { + return (Temp); + } + + // + // If we found an escaped character, try again on the remainder of the string + // + if ((Temp > (SourceString)) && *(Temp-1) == L'^') { + return FindNextInstance(Temp+1, FindString, CheckForEscapeCharacter); + } + + // + // we found the right character + // + return (Temp); +} + +/** + Check whether the string between a pair of % is a valid environment variable name. + + @param[in] BeginPercent pointer to the first percent. + @param[in] EndPercent pointer to the last percent. + + @retval TRUE is a valid environment variable name. + @retval FALSE is NOT a valid environment variable name. +**/ +BOOLEAN +IsValidEnvironmentVariableName( + IN CONST CHAR16 *BeginPercent, + IN CONST CHAR16 *EndPercent + ) +{ + CONST CHAR16 *Walker; + + Walker = NULL; + + ASSERT (BeginPercent != NULL); + ASSERT (EndPercent != NULL); + ASSERT (BeginPercent < EndPercent); + + if ((BeginPercent + 1) == EndPercent) { + return FALSE; + } + + for (Walker = BeginPercent + 1; Walker < EndPercent; Walker++) { + if ( + (*Walker >= L'0' && *Walker <= L'9') || + (*Walker >= L'A' && *Walker <= L'Z') || + (*Walker >= L'a' && *Walker <= L'z') || + (*Walker == L'_') + ) { + if (Walker == BeginPercent + 1 && (*Walker >= L'0' && *Walker <= L'9')) { + return FALSE; + } else { + continue; + } + } else { + return FALSE; + } + } + + return TRUE; +} + +/** + Determine if a command line contains a split operation + + @param[in] CmdLine The command line to parse. + + @retval TRUE CmdLine has a valid split. + @retval FALSE CmdLine does not have a valid split. +**/ +BOOLEAN +ContainsSplit( + IN CONST CHAR16 *CmdLine + ) +{ + CONST CHAR16 *TempSpot; + CONST CHAR16 *FirstQuote; + CONST CHAR16 *SecondQuote; + + FirstQuote = FindNextInstance (CmdLine, L"\"", TRUE); + SecondQuote = NULL; + TempSpot = FindFirstCharacter(CmdLine, L"|", L'^'); + + if (FirstQuote == NULL || + TempSpot == NULL || + TempSpot == CHAR_NULL || + FirstQuote > TempSpot + ) { + return (BOOLEAN) ((TempSpot != NULL) && (*TempSpot != CHAR_NULL)); + } + + while ((TempSpot != NULL) && (*TempSpot != CHAR_NULL)) { + if (FirstQuote == NULL || FirstQuote > TempSpot) { + break; + } + SecondQuote = FindNextInstance (FirstQuote + 1, L"\"", TRUE); + if (SecondQuote == NULL) { + break; + } + if (SecondQuote < TempSpot) { + FirstQuote = FindNextInstance (SecondQuote + 1, L"\"", TRUE); + continue; + } else { + FirstQuote = FindNextInstance (SecondQuote + 1, L"\"", TRUE); + TempSpot = FindFirstCharacter(TempSpot + 1, L"|", L'^'); + continue; + } + } + + return (BOOLEAN) ((TempSpot != NULL) && (*TempSpot != CHAR_NULL)); +} + +/** + Function to start monitoring for CTRL-S using SimpleTextInputEx. This + feature's enabled state was not known when the shell initially launched. + + @retval EFI_SUCCESS The feature is enabled. + @retval EFI_OUT_OF_RESOURCES There is not enough memory available. +**/ +EFI_STATUS +InternalEfiShellStartCtrlSMonitor( + VOID + ) +{ + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx; + EFI_KEY_DATA KeyData; + EFI_STATUS Status; + + Status = gBS->OpenProtocol( + gST->ConsoleInHandle, + &gEfiSimpleTextInputExProtocolGuid, + (VOID**)&SimpleEx, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_SHELL_NO_IN_EX), + ShellInfoObject.HiiHandle); + return (EFI_SUCCESS); + } + + KeyData.KeyState.KeyToggleState = 0; + KeyData.Key.ScanCode = 0; + KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED; + KeyData.Key.UnicodeChar = L's'; + + Status = SimpleEx->RegisterKeyNotify( + SimpleEx, + &KeyData, + NotificationFunction, + &ShellInfoObject.CtrlSNotifyHandle1); + + KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED; + if (!EFI_ERROR(Status)) { + Status = SimpleEx->RegisterKeyNotify( + SimpleEx, + &KeyData, + NotificationFunction, + &ShellInfoObject.CtrlSNotifyHandle2); + } + KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED; + KeyData.Key.UnicodeChar = 19; + + if (!EFI_ERROR(Status)) { + Status = SimpleEx->RegisterKeyNotify( + SimpleEx, + &KeyData, + NotificationFunction, + &ShellInfoObject.CtrlSNotifyHandle3); + } + KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED; + if (!EFI_ERROR(Status)) { + Status = SimpleEx->RegisterKeyNotify( + SimpleEx, + &KeyData, + NotificationFunction, + &ShellInfoObject.CtrlSNotifyHandle4); + } + return (Status); +} + + + +/** + The 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 + ) +{ + EFI_STATUS Status; + CHAR16 *TempString; + UINTN Size; + EFI_HANDLE ConInHandle; + EFI_SIMPLE_TEXT_INPUT_PROTOCOL *OldConIn; + SPLIT_LIST *Split; + + if (PcdGet8(PcdShellSupportLevel) > 3) { + return (EFI_UNSUPPORTED); + } + + // + // Clear the screen + // + Status = gST->ConOut->ClearScreen(gST->ConOut); + if (EFI_ERROR(Status)) { + return (Status); + } + + // + // Populate the global structure from PCDs + // + ShellInfoObject.ImageDevPath = NULL; + ShellInfoObject.FileDevPath = NULL; + ShellInfoObject.PageBreakEnabled = PcdGetBool(PcdShellPageBreakDefault); + ShellInfoObject.ViewingSettings.InsertMode = PcdGetBool(PcdShellInsertModeDefault); + ShellInfoObject.LogScreenCount = PcdGet8 (PcdShellScreenLogCount ); + + // + // verify we dont allow for spec violation + // + ASSERT(ShellInfoObject.LogScreenCount >= 3); + + // + // Initialize the LIST ENTRY objects... + // + InitializeListHead(&ShellInfoObject.BufferToFreeList.Link); + InitializeListHead(&ShellInfoObject.ViewingSettings.CommandHistory.Link); + InitializeListHead(&ShellInfoObject.SplitList.Link); + + // + // Check PCDs for optional features that are not implemented yet. + // + if ( PcdGetBool(PcdShellSupportOldProtocols) + || !FeaturePcdGet(PcdShellRequireHiiPlatform) + || FeaturePcdGet(PcdShellSupportFrameworkHii) + ) { + return (EFI_UNSUPPORTED); + } + + // + // turn off the watchdog timer + // + gBS->SetWatchdogTimer (0, 0, 0, NULL); + + // + // install our console logger. This will keep a log of the output for back-browsing + // + Status = ConsoleLoggerInstall(ShellInfoObject.LogScreenCount, &ShellInfoObject.ConsoleInfo); + if (!EFI_ERROR(Status)) { + // + // Enable the cursor to be visible + // + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + + // + // If supporting EFI 1.1 we need to install HII protocol + // only do this if PcdShellRequireHiiPlatform == FALSE + // + // remove EFI_UNSUPPORTED check above when complete. + ///@todo add support for Framework HII + + // + // install our (solitary) HII package + // + ShellInfoObject.HiiHandle = HiiAddPackages (&gEfiCallerIdGuid, gImageHandle, ShellStrings, NULL); + if (ShellInfoObject.HiiHandle == NULL) { + if (PcdGetBool(PcdShellSupportFrameworkHii)) { + ///@todo Add our package into Framework HII + } + if (ShellInfoObject.HiiHandle == NULL) { + Status = EFI_NOT_STARTED; + goto FreeResources; + } + } + + // + // create and install the EfiShellParametersProtocol + // + Status = CreatePopulateInstallShellParametersProtocol(&ShellInfoObject.NewShellParametersProtocol, &ShellInfoObject.RootShellInstance); + ASSERT_EFI_ERROR(Status); + ASSERT(ShellInfoObject.NewShellParametersProtocol != NULL); + + // + // create and install the EfiShellProtocol + // + Status = CreatePopulateInstallShellProtocol(&ShellInfoObject.NewEfiShellProtocol); + ASSERT_EFI_ERROR(Status); + ASSERT(ShellInfoObject.NewEfiShellProtocol != NULL); + + // + // Now initialize the shell library (it requires Shell Parameters protocol) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + Status = ShellInitEnvVarList (); + + // + // Check the command line + // + Status = ProcessCommandLine (); + if (EFI_ERROR (Status)) { + goto FreeResources; + } + + // + // If shell support level is >= 1 create the mappings and paths + // + if (PcdGet8(PcdShellSupportLevel) >= 1) { + Status = ShellCommandCreateInitialMappingsAndPaths(); + } + + // + // Set the environment variable for nesting support + // + Size = 0; + TempString = NULL; + if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoNest) { + // + // No change. require nesting in Shell Protocol Execute() + // + StrnCatGrow(&TempString, + &Size, + L"False", + 0); + } else { + StrnCatGrow(&TempString, + &Size, + mNoNestingTrue, + 0); + } + Status = InternalEfiShellSetEnv(mNoNestingEnvVarName, TempString, TRUE); + SHELL_FREE_NON_NULL(TempString); + Size = 0; + + // + // save the device path for the loaded image and the device path for the filepath (under loaded image) + // These are where to look for the startup.nsh file + // + Status = GetDevicePathsForImageAndFile(&ShellInfoObject.ImageDevPath, &ShellInfoObject.FileDevPath); + ASSERT_EFI_ERROR(Status); + + // + // Display the version + // + if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoVersion) { + ShellPrintHiiEx ( + 0, + gST->ConOut->Mode->CursorRow, + NULL, + STRING_TOKEN (STR_VER_OUTPUT_MAIN_SHELL), + ShellInfoObject.HiiHandle, + SupportLevel[PcdGet8(PcdShellSupportLevel)], + gEfiShellProtocol->MajorVersion, + gEfiShellProtocol->MinorVersion + ); + + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_VER_OUTPUT_MAIN_SUPPLIER), + ShellInfoObject.HiiHandle, + (CHAR16 *) PcdGetPtr (PcdShellSupplier) + ); + + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_VER_OUTPUT_MAIN_UEFI), + ShellInfoObject.HiiHandle, + (gST->Hdr.Revision&0xffff0000)>>16, + (gST->Hdr.Revision&0x0000ffff), + gST->FirmwareVendor, + gST->FirmwareRevision + ); + } + + // + // Display the mapping + // + if (PcdGet8(PcdShellSupportLevel) >= 2 && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoMap) { + Status = RunCommand(L"map"); + ASSERT_EFI_ERROR(Status); + } + + // + // init all the built in alias' + // + Status = SetBuiltInAlias(); + ASSERT_EFI_ERROR(Status); + + // + // Initialize environment variables + // + if (ShellCommandGetProfileList() != NULL) { + Status = InternalEfiShellSetEnv(L"profiles", ShellCommandGetProfileList(), TRUE); + ASSERT_EFI_ERROR(Status); + } + + Size = 100; + TempString = AllocateZeroPool(Size); + + UnicodeSPrint(TempString, Size, L"%d", PcdGet8(PcdShellSupportLevel)); + Status = InternalEfiShellSetEnv(L"uefishellsupport", TempString, TRUE); + ASSERT_EFI_ERROR(Status); + + UnicodeSPrint(TempString, Size, L"%d.%d", ShellInfoObject.NewEfiShellProtocol->MajorVersion, ShellInfoObject.NewEfiShellProtocol->MinorVersion); + Status = InternalEfiShellSetEnv(L"uefishellversion", TempString, TRUE); + ASSERT_EFI_ERROR(Status); + + UnicodeSPrint(TempString, Size, L"%d.%d", (gST->Hdr.Revision & 0xFFFF0000) >> 16, gST->Hdr.Revision & 0x0000FFFF); + Status = InternalEfiShellSetEnv(L"uefiversion", TempString, TRUE); + ASSERT_EFI_ERROR(Status); + + FreePool(TempString); + + if (!EFI_ERROR(Status)) { + if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoInterrupt) { + // + // Set up the event for CTRL-C monitoring... + // + Status = InernalEfiShellStartMonitor(); + } + + if (!EFI_ERROR(Status) && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn) { + // + // Set up the event for CTRL-S monitoring... + // + Status = InternalEfiShellStartCtrlSMonitor(); + } + + if (!EFI_ERROR(Status) && ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn) { + // + // close off the gST->ConIn + // + OldConIn = gST->ConIn; + ConInHandle = gST->ConsoleInHandle; + gST->ConIn = CreateSimpleTextInOnFile((SHELL_FILE_HANDLE)&FileInterfaceNulFile, &gST->ConsoleInHandle); + } else { + OldConIn = NULL; + ConInHandle = NULL; + } + + if (!EFI_ERROR(Status) && PcdGet8(PcdShellSupportLevel) >= 1) { + // + // process the startup script or launch the called app. + // + Status = DoStartupScript(ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath); + } + + if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit && !ShellCommandGetExit() && (PcdGet8(PcdShellSupportLevel) >= 3 || PcdGetBool(PcdShellForceConsole)) && !EFI_ERROR(Status) && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn) { + // + // begin the UI waiting loop + // + do { + // + // clean out all the memory allocated for CONST * return values + // between each shell prompt presentation + // + if (!IsListEmpty(&ShellInfoObject.BufferToFreeList.Link)){ + FreeBufferList(&ShellInfoObject.BufferToFreeList); + } + + // + // Reset page break back to default. + // + ShellInfoObject.PageBreakEnabled = PcdGetBool(PcdShellPageBreakDefault); + ASSERT (ShellInfoObject.ConsoleInfo != NULL); + ShellInfoObject.ConsoleInfo->Enabled = TRUE; + ShellInfoObject.ConsoleInfo->RowCounter = 0; + + // + // Display Prompt + // + Status = DoShellPrompt(); + } while (!ShellCommandGetExit()); + } + if (OldConIn != NULL && ConInHandle != NULL) { + CloseSimpleTextInOnFile (gST->ConIn); + gST->ConIn = OldConIn; + gST->ConsoleInHandle = ConInHandle; + } + } + } + +FreeResources: + // + // uninstall protocols / free memory / etc... + // + if (ShellInfoObject.UserBreakTimer != NULL) { + gBS->CloseEvent(ShellInfoObject.UserBreakTimer); + DEBUG_CODE(ShellInfoObject.UserBreakTimer = NULL;); + } + if (ShellInfoObject.ImageDevPath != NULL) { + FreePool(ShellInfoObject.ImageDevPath); + DEBUG_CODE(ShellInfoObject.ImageDevPath = NULL;); + } + if (ShellInfoObject.FileDevPath != NULL) { + FreePool(ShellInfoObject.FileDevPath); + DEBUG_CODE(ShellInfoObject.FileDevPath = NULL;); + } + if (ShellInfoObject.NewShellParametersProtocol != NULL) { + CleanUpShellParametersProtocol(ShellInfoObject.NewShellParametersProtocol); + DEBUG_CODE(ShellInfoObject.NewShellParametersProtocol = NULL;); + } + if (ShellInfoObject.NewEfiShellProtocol != NULL){ + if (ShellInfoObject.NewEfiShellProtocol->IsRootShell()){ + InternalEfiShellSetEnv(L"cwd", NULL, TRUE); + } + CleanUpShellEnvironment (ShellInfoObject.NewEfiShellProtocol); + DEBUG_CODE(ShellInfoObject.NewEfiShellProtocol = NULL;); + } + + if (!IsListEmpty(&ShellInfoObject.BufferToFreeList.Link)){ + FreeBufferList(&ShellInfoObject.BufferToFreeList); + } + + if (!IsListEmpty(&ShellInfoObject.SplitList.Link)){ + ASSERT(FALSE); ///@todo finish this de-allocation (free SplitStdIn/Out when needed). + + for ( Split = (SPLIT_LIST*)GetFirstNode (&ShellInfoObject.SplitList.Link) + ; !IsNull (&ShellInfoObject.SplitList.Link, &Split->Link) + ; Split = (SPLIT_LIST *)GetNextNode (&ShellInfoObject.SplitList.Link, &Split->Link) + ) { + RemoveEntryList (&Split->Link); + FreePool (Split); + } + + DEBUG_CODE (InitializeListHead (&ShellInfoObject.SplitList.Link);); + } + + if (ShellInfoObject.ShellInitSettings.FileName != NULL) { + FreePool(ShellInfoObject.ShellInitSettings.FileName); + DEBUG_CODE(ShellInfoObject.ShellInitSettings.FileName = NULL;); + } + + if (ShellInfoObject.ShellInitSettings.FileOptions != NULL) { + FreePool(ShellInfoObject.ShellInitSettings.FileOptions); + DEBUG_CODE(ShellInfoObject.ShellInitSettings.FileOptions = NULL;); + } + + if (ShellInfoObject.HiiHandle != NULL) { + HiiRemovePackages(ShellInfoObject.HiiHandle); + DEBUG_CODE(ShellInfoObject.HiiHandle = NULL;); + } + + if (!IsListEmpty(&ShellInfoObject.ViewingSettings.CommandHistory.Link)){ + FreeBufferList(&ShellInfoObject.ViewingSettings.CommandHistory); + } + + ASSERT(ShellInfoObject.ConsoleInfo != NULL); + if (ShellInfoObject.ConsoleInfo != NULL) { + ConsoleLoggerUninstall(ShellInfoObject.ConsoleInfo); + FreePool(ShellInfoObject.ConsoleInfo); + DEBUG_CODE(ShellInfoObject.ConsoleInfo = NULL;); + } + + ShellFreeEnvVarList (); + + if (ShellCommandGetExit()) { + return ((EFI_STATUS)ShellCommandGetExitCode()); + } + return (Status); +} + +/** + Sets all the alias' that were registered with the ShellCommandLib library. + + @retval EFI_SUCCESS all init commands were run successfully. +**/ +EFI_STATUS +SetBuiltInAlias( + VOID + ) +{ + EFI_STATUS Status; + CONST ALIAS_LIST *List; + ALIAS_LIST *Node; + + // + // Get all the commands we want to run + // + List = ShellCommandGetInitAliasList(); + + // + // for each command in the List + // + for ( Node = (ALIAS_LIST*)GetFirstNode(&List->Link) + ; !IsNull (&List->Link, &Node->Link) + ; Node = (ALIAS_LIST *)GetNextNode(&List->Link, &Node->Link) + ){ + // + // install the alias' + // + Status = InternalSetAlias(Node->CommandString, Node->Alias, TRUE); + ASSERT_EFI_ERROR(Status); + } + return (EFI_SUCCESS); +} + +/** + Internal function to determine if 2 command names are really the same. + + @param[in] Command1 The pointer to the first command name. + @param[in] Command2 The pointer to the second command name. + + @retval TRUE The 2 command names are the same. + @retval FALSE The 2 command names are not the same. +**/ +BOOLEAN +IsCommand( + IN CONST CHAR16 *Command1, + IN CONST CHAR16 *Command2 + ) +{ + if (StringNoCaseCompare(&Command1, &Command2) == 0) { + return (TRUE); + } + return (FALSE); +} + +/** + Internal function to determine if a command is a script only command. + + @param[in] CommandName The pointer to the command name. + + @retval TRUE The command is a script only command. + @retval FALSE The command is not a script only command. +**/ +BOOLEAN +IsScriptOnlyCommand( + IN CONST CHAR16 *CommandName + ) +{ + if (IsCommand(CommandName, L"for") + ||IsCommand(CommandName, L"endfor") + ||IsCommand(CommandName, L"if") + ||IsCommand(CommandName, L"else") + ||IsCommand(CommandName, L"endif") + ||IsCommand(CommandName, L"goto")) { + return (TRUE); + } + return (FALSE); +} + +/** + This function will populate the 2 device path protocol parameters based on the + global gImageHandle. The DevPath will point to the device path for the handle that has + loaded image protocol installed on it. The FilePath will point to the device path + for the file that was loaded. + + @param[in, out] DevPath On a successful return the device path to the loaded image. + @param[in, out] FilePath On a successful return the device path to the file. + + @retval EFI_SUCCESS The 2 device paths were successfully returned. + @retval other A error from gBS->HandleProtocol. + + @sa HandleProtocol +**/ +EFI_STATUS +GetDevicePathsForImageAndFile ( + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevPath, + IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath + ) +{ + EFI_STATUS Status; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath; + + ASSERT(DevPath != NULL); + ASSERT(FilePath != NULL); + + Status = gBS->OpenProtocol ( + gImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID**)&LoadedImage, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + Status = gBS->OpenProtocol ( + LoadedImage->DeviceHandle, + &gEfiDevicePathProtocolGuid, + (VOID**)&ImageDevicePath, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + *DevPath = DuplicateDevicePath (ImageDevicePath); + *FilePath = DuplicateDevicePath (LoadedImage->FilePath); + gBS->CloseProtocol( + LoadedImage->DeviceHandle, + &gEfiDevicePathProtocolGuid, + gImageHandle, + NULL); + } + gBS->CloseProtocol( + gImageHandle, + &gEfiLoadedImageProtocolGuid, + gImageHandle, + NULL); + } + return (Status); +} + +/** + Process all Uefi Shell 2.0 command line options. + + see Uefi Shell 2.0 section 3.2 for full details. + + the command line must resemble the following: + + shell.efi [ShellOpt-options] [options] [file-name [file-name-options]] + + ShellOpt-options Options which control the initialization behavior of the shell. + These options are read from the EFI global variable "ShellOpt" + and are processed before options or file-name. + + options Options which control the initialization behavior of the shell. + + file-name The name of a UEFI shell application or script to be executed + after initialization is complete. By default, if file-name is + specified, then -nostartup is implied. Scripts are not supported + by level 0. + + file-name-options The command-line options that are passed to file-name when it + is invoked. + + This will initialize the ShellInfoObject.ShellInitSettings global variable. + + @retval EFI_SUCCESS The variable is initialized. +**/ +EFI_STATUS +ProcessCommandLine( + VOID + ) +{ + UINTN Size; + UINTN LoopVar; + CHAR16 *CurrentArg; + CHAR16 *DelayValueStr; + UINT64 DelayValue; + EFI_STATUS Status; + EFI_UNICODE_COLLATION_PROTOCOL *UnicodeCollation; + + // `file-name-options` will contain arguments to `file-name` that we don't + // know about. This would cause ShellCommandLineParse to error, so we parse + // arguments manually, ignoring those after the first thing that doesn't look + // like a shell option (which is assumed to be `file-name`). + + Status = gBS->LocateProtocol ( + &gEfiUnicodeCollation2ProtocolGuid, + NULL, + (VOID **) &UnicodeCollation + ); + if (EFI_ERROR (Status)) { + Status = gBS->LocateProtocol ( + &gEfiUnicodeCollationProtocolGuid, + NULL, + (VOID **) &UnicodeCollation + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // Set default options + ShellInfoObject.ShellInitSettings.BitUnion.Bits.Startup = FALSE; + ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoStartup = FALSE; + ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut = FALSE; + ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn = FALSE; + ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoInterrupt = FALSE; + ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoMap = FALSE; + ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoVersion = FALSE; + ShellInfoObject.ShellInitSettings.BitUnion.Bits.Delay = FALSE; + ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit = FALSE; + ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoNest = FALSE; + ShellInfoObject.ShellInitSettings.Delay = 5; + + // + // Start LoopVar at 0 to parse only optional arguments at Argv[0] + // and parse other parameters from Argv[1]. This is for use case that + // UEFI Shell boot option is created, and OptionalData is provided + // that starts with shell command-line options. + // + for (LoopVar = 0 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) { + CurrentArg = gEfiShellParametersProtocol->Argv[LoopVar]; + if (UnicodeCollation->StriColl ( + UnicodeCollation, + L"-startup", + CurrentArg + ) == 0) { + ShellInfoObject.ShellInitSettings.BitUnion.Bits.Startup = TRUE; + } + else if (UnicodeCollation->StriColl ( + UnicodeCollation, + L"-nostartup", + CurrentArg + ) == 0) { + ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoStartup = TRUE; + } + else if (UnicodeCollation->StriColl ( + UnicodeCollation, + L"-noconsoleout", + CurrentArg + ) == 0) { + ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut = TRUE; + } + else if (UnicodeCollation->StriColl ( + UnicodeCollation, + L"-noconsolein", + CurrentArg + ) == 0) { + ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn = TRUE; + } + else if (UnicodeCollation->StriColl ( + UnicodeCollation, + L"-nointerrupt", + CurrentArg + ) == 0) { + ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoInterrupt = TRUE; + } + else if (UnicodeCollation->StriColl ( + UnicodeCollation, + L"-nomap", + CurrentArg + ) == 0) { + ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoMap = TRUE; + } + else if (UnicodeCollation->StriColl ( + UnicodeCollation, + L"-noversion", + CurrentArg + ) == 0) { + ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoVersion = TRUE; + } + else if (UnicodeCollation->StriColl ( + UnicodeCollation, + L"-nonest", + CurrentArg + ) == 0) { + ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoNest = TRUE; + } + else if (UnicodeCollation->StriColl ( + UnicodeCollation, + L"-delay", + CurrentArg + ) == 0) { + ShellInfoObject.ShellInitSettings.BitUnion.Bits.Delay = TRUE; + // Check for optional delay value following "-delay" + if ((LoopVar + 1) >= gEfiShellParametersProtocol->Argc) { + DelayValueStr = NULL; + } else { + DelayValueStr = gEfiShellParametersProtocol->Argv[LoopVar + 1]; + } + if (DelayValueStr != NULL){ + if (*DelayValueStr == L':') { + DelayValueStr++; + } + if (!EFI_ERROR(ShellConvertStringToUint64 ( + DelayValueStr, + &DelayValue, + FALSE, + FALSE + ))) { + ShellInfoObject.ShellInitSettings.Delay = (UINTN)DelayValue; + LoopVar++; + } + } + } else if (UnicodeCollation->StriColl ( + UnicodeCollation, + L"-exit", + CurrentArg + ) == 0) { + ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit = TRUE; + } else if (StrnCmp (L"-", CurrentArg, 1) == 0) { + // Unrecognized option + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_GEN_PROBLEM), + ShellInfoObject.HiiHandle, + CurrentArg + ); + return EFI_INVALID_PARAMETER; + } else { + // + // First argument should be Shell.efi image name + // + if (LoopVar == 0) { + continue; + } + + ShellInfoObject.ShellInitSettings.FileName = NULL; + Size = 0; + // + // If first argument contains a space, then add double quotes before the argument + // + if (StrStr (CurrentArg, L" ") != NULL) { + StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileName, &Size, L"\"", 0); + if (ShellInfoObject.ShellInitSettings.FileName == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + } + StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileName, &Size, CurrentArg, 0); + if (ShellInfoObject.ShellInitSettings.FileName == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + // + // If first argument contains a space, then add double quotes after the argument + // + if (StrStr (CurrentArg, L" ") != NULL) { + StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileName, &Size, L"\"", 0); + if (ShellInfoObject.ShellInitSettings.FileName == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + } + // + // We found `file-name`. + // + ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoStartup = 1; + LoopVar++; + + // Add `file-name-options` + for (Size = 0 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) { + ASSERT((ShellInfoObject.ShellInitSettings.FileOptions == NULL && Size == 0) || (ShellInfoObject.ShellInitSettings.FileOptions != NULL)); + // + // Add a space between arguments + // + if (ShellInfoObject.ShellInitSettings.FileOptions != NULL) { + StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions, &Size, L" ", 0); + if (ShellInfoObject.ShellInitSettings.FileOptions == NULL) { + SHELL_FREE_NON_NULL(ShellInfoObject.ShellInitSettings.FileName); + return (EFI_OUT_OF_RESOURCES); + } + } + // + // If an argument contains a space, then add double quotes before the argument + // + if (StrStr (gEfiShellParametersProtocol->Argv[LoopVar], L" ") != NULL) { + StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions, + &Size, + L"\"", + 0); + if (ShellInfoObject.ShellInitSettings.FileOptions == NULL) { + SHELL_FREE_NON_NULL(ShellInfoObject.ShellInitSettings.FileName); + return (EFI_OUT_OF_RESOURCES); + } + } + StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions, + &Size, + gEfiShellParametersProtocol->Argv[LoopVar], + 0); + if (ShellInfoObject.ShellInitSettings.FileOptions == NULL) { + SHELL_FREE_NON_NULL(ShellInfoObject.ShellInitSettings.FileName); + return (EFI_OUT_OF_RESOURCES); + } + // + // If an argument contains a space, then add double quotes after the argument + // + if (StrStr (gEfiShellParametersProtocol->Argv[LoopVar], L" ") != NULL) { + StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions, + &Size, + L"\"", + 0); + if (ShellInfoObject.ShellInitSettings.FileOptions == NULL) { + SHELL_FREE_NON_NULL(ShellInfoObject.ShellInitSettings.FileName); + return (EFI_OUT_OF_RESOURCES); + } + } + } + } + } + + // "-nointerrupt" overrides "-delay" + if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoInterrupt) { + ShellInfoObject.ShellInitSettings.Delay = 0; + } + + return EFI_SUCCESS; +} + +/** + Function try to find location of the Startup.nsh file. + + The buffer is callee allocated and should be freed by the caller. + + @param ImageDevicePath The path to the image for shell. first place to look for the startup script + @param FileDevicePath The path to the file for shell. second place to look for the startup script. + + @retval NULL No Startup.nsh file was found. + @return !=NULL Pointer to NULL-terminated path. +**/ +CHAR16 * +LocateStartupScript ( + IN EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath, + IN EFI_DEVICE_PATH_PROTOCOL *FileDevicePath + ) +{ + CHAR16 *StartupScriptPath; + CHAR16 *TempSpot; + CONST CHAR16 *MapName; + UINTN Size; + + StartupScriptPath = NULL; + Size = 0; + + // + // Try to find 'Startup.nsh' in the directory where the shell itself was launched. + // + MapName = ShellInfoObject.NewEfiShellProtocol->GetMapFromDevicePath (&ImageDevicePath); + if (MapName != NULL) { + StartupScriptPath = StrnCatGrow (&StartupScriptPath, &Size, MapName, 0); + if (StartupScriptPath == NULL) { + // + // Do not locate the startup script in sys path when out of resource. + // + return NULL; + } + TempSpot = StrStr (StartupScriptPath, L";"); + if (TempSpot != NULL) { + *TempSpot = CHAR_NULL; + } + + InternalEfiShellSetEnv(L"homefilesystem", StartupScriptPath, TRUE); + + StartupScriptPath = StrnCatGrow (&StartupScriptPath, &Size, ((FILEPATH_DEVICE_PATH *)FileDevicePath)->PathName, 0); + PathRemoveLastItem (StartupScriptPath); + StartupScriptPath = StrnCatGrow (&StartupScriptPath, &Size, mStartupScript, 0); + } + + // + // Try to find 'Startup.nsh' in the execution path defined by the environment variable PATH. + // + if ((StartupScriptPath == NULL) || EFI_ERROR (ShellIsFile (StartupScriptPath))) { + SHELL_FREE_NON_NULL (StartupScriptPath); + StartupScriptPath = ShellFindFilePath (mStartupScript); + } + + return StartupScriptPath; +} + +/** + Handles all interaction with the default startup script. + + this will check that the correct command line parameters were passed, handle the delay, and then start running the script. + + @param ImagePath the path to the image for shell. first place to look for the startup script + @param FilePath the path to the file for shell. second place to look for the startup script. + + @retval EFI_SUCCESS the variable is initialized. +**/ +EFI_STATUS +DoStartupScript( + IN EFI_DEVICE_PATH_PROTOCOL *ImagePath, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath + ) +{ + EFI_STATUS Status; + EFI_STATUS CalleeStatus; + UINTN Delay; + EFI_INPUT_KEY Key; + CHAR16 *FileStringPath; + CHAR16 *FullFileStringPath; + UINTN NewSize; + + Key.UnicodeChar = CHAR_NULL; + Key.ScanCode = 0; + + if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.Startup && ShellInfoObject.ShellInitSettings.FileName != NULL) { + // + // launch something else instead + // + NewSize = StrSize(ShellInfoObject.ShellInitSettings.FileName); + if (ShellInfoObject.ShellInitSettings.FileOptions != NULL) { + NewSize += StrSize(ShellInfoObject.ShellInitSettings.FileOptions) + sizeof(CHAR16); + } + FileStringPath = AllocateZeroPool(NewSize); + if (FileStringPath == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + StrCpyS(FileStringPath, NewSize/sizeof(CHAR16), ShellInfoObject.ShellInitSettings.FileName); + if (ShellInfoObject.ShellInitSettings.FileOptions != NULL) { + StrnCatS(FileStringPath, NewSize/sizeof(CHAR16), L" ", NewSize/sizeof(CHAR16) - StrLen(FileStringPath) -1); + StrnCatS(FileStringPath, NewSize/sizeof(CHAR16), ShellInfoObject.ShellInitSettings.FileOptions, NewSize/sizeof(CHAR16) - StrLen(FileStringPath) -1); + } + Status = RunShellCommand(FileStringPath, &CalleeStatus); + if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit == TRUE) { + ShellCommandRegisterExit(gEfiShellProtocol->BatchIsActive(), (UINT64)CalleeStatus); + } + FreePool(FileStringPath); + return (Status); + + } + + // + // for shell level 0 we do no scripts + // Without the Startup bit overriding we allow for nostartup to prevent scripts + // + if ( (PcdGet8(PcdShellSupportLevel) < 1) + || (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoStartup && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.Startup) + ){ + return (EFI_SUCCESS); + } + + gST->ConOut->EnableCursor(gST->ConOut, FALSE); + // + // print out our warning and see if they press a key + // + for ( Status = EFI_UNSUPPORTED, Delay = ShellInfoObject.ShellInitSettings.Delay + ; Delay != 0 && EFI_ERROR(Status) + ; Delay-- + ){ + ShellPrintHiiEx(0, gST->ConOut->Mode->CursorRow, NULL, STRING_TOKEN (STR_SHELL_STARTUP_QUESTION), ShellInfoObject.HiiHandle, Delay); + gBS->Stall (1000000); + if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn) { + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + } + } + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_CRLF), ShellInfoObject.HiiHandle); + gST->ConOut->EnableCursor(gST->ConOut, TRUE); + + // + // ESC was pressed + // + if (Status == EFI_SUCCESS && Key.UnicodeChar == 0 && Key.ScanCode == SCAN_ESC) { + return (EFI_SUCCESS); + } + + FileStringPath = LocateStartupScript (ImagePath, FilePath); + if (FileStringPath != NULL) { + FullFileStringPath = FullyQualifyPath(FileStringPath); + if (FullFileStringPath == NULL) { + Status = RunScriptFile (FileStringPath, NULL, FileStringPath, ShellInfoObject.NewShellParametersProtocol); + } else { + Status = RunScriptFile (FullFileStringPath, NULL, FullFileStringPath, ShellInfoObject.NewShellParametersProtocol); + FreePool(FullFileStringPath); + } + FreePool (FileStringPath); + } else { + // + // we return success since startup script is not mandatory. + // + Status = EFI_SUCCESS; + } + + return (Status); +} + +/** + Function to perform the shell prompt looping. It will do a single prompt, + dispatch the result, and then return. It is expected that the caller will + call this function in a loop many times. + + @retval EFI_SUCCESS + @retval RETURN_ABORTED +**/ +EFI_STATUS +DoShellPrompt ( + VOID + ) +{ + UINTN Column; + UINTN Row; + CHAR16 *CmdLine; + CONST CHAR16 *CurDir; + UINTN BufferSize; + EFI_STATUS Status; + LIST_ENTRY OldBufferList; + + CurDir = NULL; + + // + // Get screen setting to decide size of the command line buffer + // + gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &Column, &Row); + BufferSize = Column * Row * sizeof (CHAR16); + CmdLine = AllocateZeroPool (BufferSize); + if (CmdLine == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + SaveBufferList(&OldBufferList); + CurDir = ShellInfoObject.NewEfiShellProtocol->GetEnv(L"cwd"); + + // + // Prompt for input + // + gST->ConOut->SetCursorPosition (gST->ConOut, 0, gST->ConOut->Mode->CursorRow); + + if (CurDir != NULL && StrLen(CurDir) > 1) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_CURDIR), ShellInfoObject.HiiHandle, CurDir); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_SHELL), ShellInfoObject.HiiHandle); + } + + // + // Read a line from the console + // + Status = ShellInfoObject.NewEfiShellProtocol->ReadFile(ShellInfoObject.NewShellParametersProtocol->StdIn, &BufferSize, CmdLine); + + // + // Null terminate the string and parse it + // + if (!EFI_ERROR (Status)) { + // + // Reset the CTRL-C event just before running the command (yes we ignore the return values) + // + Status = gBS->CheckEvent (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak); + + CmdLine[BufferSize / sizeof (CHAR16)] = CHAR_NULL; + Status = RunCommand(CmdLine); + } + + // + // Done with this command + // + RestoreBufferList(&OldBufferList); + FreePool (CmdLine); + return Status; +} + +/** + Add a buffer to the Buffer To Free List for safely returning buffers to other + places without risking letting them modify internal shell information. + + @param Buffer Something to pass to FreePool when the shell is exiting. +**/ +VOID* +AddBufferToFreeList ( + VOID *Buffer + ) +{ + BUFFER_LIST *BufferListEntry; + + if (Buffer == NULL) { + return (NULL); + } + + BufferListEntry = AllocateZeroPool (sizeof (BUFFER_LIST)); + if (BufferListEntry == NULL) { + return NULL; + } + + BufferListEntry->Buffer = Buffer; + InsertTailList (&ShellInfoObject.BufferToFreeList.Link, &BufferListEntry->Link); + return (Buffer); +} + + +/** + Create a new buffer list and stores the old one to OldBufferList + + @param OldBufferList The temporary list head used to store the nodes in BufferToFreeList. +**/ +VOID +SaveBufferList ( + OUT LIST_ENTRY *OldBufferList + ) +{ + CopyMem (OldBufferList, &ShellInfoObject.BufferToFreeList.Link, sizeof (LIST_ENTRY)); + InitializeListHead (&ShellInfoObject.BufferToFreeList.Link); +} + +/** + Restore previous nodes into BufferToFreeList . + + @param OldBufferList The temporary list head used to store the nodes in BufferToFreeList. +**/ +VOID +RestoreBufferList ( + IN OUT LIST_ENTRY *OldBufferList + ) +{ + FreeBufferList (&ShellInfoObject.BufferToFreeList); + CopyMem (&ShellInfoObject.BufferToFreeList.Link, OldBufferList, sizeof (LIST_ENTRY)); +} + + +/** + Add a buffer to the Line History List + + @param Buffer The line buffer to add. +**/ +VOID +AddLineToCommandHistory( + IN CONST CHAR16 *Buffer + ) +{ + BUFFER_LIST *Node; + BUFFER_LIST *Walker; + UINT16 MaxHistoryCmdCount; + UINT16 Count; + + Count = 0; + MaxHistoryCmdCount = PcdGet16(PcdShellMaxHistoryCommandCount); + + if (MaxHistoryCmdCount == 0) { + return ; + } + + + Node = AllocateZeroPool(sizeof(BUFFER_LIST)); + if (Node == NULL) { + return; + } + + Node->Buffer = AllocateCopyPool (StrSize (Buffer), Buffer); + if (Node->Buffer == NULL) { + FreePool (Node); + return; + } + + for ( Walker = (BUFFER_LIST*)GetFirstNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link) + ; !IsNull(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Walker->Link) + ; Walker = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Walker->Link) + ){ + Count++; + } + if (Count < MaxHistoryCmdCount){ + InsertTailList(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link); + } else { + Walker = (BUFFER_LIST*)GetFirstNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link); + RemoveEntryList(&Walker->Link); + if (Walker->Buffer != NULL) { + FreePool(Walker->Buffer); + } + FreePool(Walker); + InsertTailList(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link); + } +} + +/** + Checks if a string is an alias for another command. If yes, then it replaces the alias name + with the correct command name. + + @param[in, out] CommandString Upon entry the potential alias. Upon return the + command name if it was an alias. If it was not + an alias it will be unchanged. This function may + change the buffer to fit the command name. + + @retval EFI_SUCCESS The name was changed. + @retval EFI_SUCCESS The name was not an alias. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +ShellConvertAlias( + IN OUT CHAR16 **CommandString + ) +{ + CONST CHAR16 *NewString; + + NewString = ShellInfoObject.NewEfiShellProtocol->GetAlias(*CommandString, NULL); + if (NewString == NULL) { + return (EFI_SUCCESS); + } + FreePool(*CommandString); + *CommandString = AllocateCopyPool(StrSize(NewString), NewString); + if (*CommandString == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + return (EFI_SUCCESS); +} + +/** + This function will eliminate unreplaced (and therefore non-found) environment variables. + + @param[in,out] CmdLine The command line to update. +**/ +EFI_STATUS +StripUnreplacedEnvironmentVariables( + IN OUT CHAR16 *CmdLine + ) +{ + CHAR16 *FirstPercent; + CHAR16 *FirstQuote; + CHAR16 *SecondPercent; + CHAR16 *SecondQuote; + CHAR16 *CurrentLocator; + + for (CurrentLocator = CmdLine ; CurrentLocator != NULL ; ) { + FirstQuote = FindNextInstance(CurrentLocator, L"\"", TRUE); + FirstPercent = FindNextInstance(CurrentLocator, L"%", TRUE); + SecondPercent = FirstPercent!=NULL?FindNextInstance(FirstPercent+1, L"%", TRUE):NULL; + if (FirstPercent == NULL || SecondPercent == NULL) { + // + // If we ever don't have 2 % we are done. + // + break; + } + + if (FirstQuote!= NULL && FirstQuote < FirstPercent) { + SecondQuote = FindNextInstance(FirstQuote+1, L"\"", TRUE); + // + // Quote is first found + // + + if (SecondQuote < FirstPercent) { + // + // restart after the pair of " + // + CurrentLocator = SecondQuote + 1; + } else /* FirstPercent < SecondQuote */{ + // + // Restart on the first percent + // + CurrentLocator = FirstPercent; + } + continue; + } + + if (FirstQuote == NULL || SecondPercent < FirstQuote) { + if (IsValidEnvironmentVariableName(FirstPercent, SecondPercent)) { + // + // We need to remove from FirstPercent to SecondPercent + // + CopyMem(FirstPercent, SecondPercent + 1, StrSize(SecondPercent + 1)); + // + // don't need to update the locator. both % characters are gone. + // + } else { + CurrentLocator = SecondPercent + 1; + } + continue; + } + CurrentLocator = FirstQuote; + } + return (EFI_SUCCESS); +} + +/** + Function allocates a new command line and replaces all instances of environment + variable names that are correctly preset to their values. + + If the return value is not NULL the memory must be caller freed. + + @param[in] OriginalCommandLine The original command line + + @retval NULL An error occurred. + @return The new command line with no environment variables present. +**/ +CHAR16* +ShellConvertVariables ( + IN CONST CHAR16 *OriginalCommandLine + ) +{ + CONST CHAR16 *MasterEnvList; + UINTN NewSize; + CHAR16 *NewCommandLine1; + CHAR16 *NewCommandLine2; + CHAR16 *Temp; + UINTN ItemSize; + CHAR16 *ItemTemp; + SCRIPT_FILE *CurrentScriptFile; + ALIAS_LIST *AliasListNode; + + ASSERT(OriginalCommandLine != NULL); + + ItemSize = 0; + NewSize = StrSize(OriginalCommandLine); + CurrentScriptFile = ShellCommandGetCurrentScriptFile(); + Temp = NULL; + + ///@todo update this to handle the %0 - %9 for scripting only (borrow from line 1256 area) ? ? ? + + // + // calculate the size required for the post-conversion string... + // + if (CurrentScriptFile != NULL) { + for (AliasListNode = (ALIAS_LIST*)GetFirstNode(&CurrentScriptFile->SubstList) + ; !IsNull(&CurrentScriptFile->SubstList, &AliasListNode->Link) + ; AliasListNode = (ALIAS_LIST*)GetNextNode(&CurrentScriptFile->SubstList, &AliasListNode->Link) + ){ + for (Temp = StrStr(OriginalCommandLine, AliasListNode->Alias) + ; Temp != NULL + ; Temp = StrStr(Temp+1, AliasListNode->Alias) + ){ + // + // we need a preceding and if there is space no ^ preceding (if no space ignore) + // + if ((((Temp-OriginalCommandLine)>2) && *(Temp-2) != L'^') || ((Temp-OriginalCommandLine)<=2)) { + NewSize += StrSize(AliasListNode->CommandString); + } + } + } + } + + for (MasterEnvList = EfiShellGetEnv(NULL) + ; MasterEnvList != NULL && *MasterEnvList != CHAR_NULL //&& *(MasterEnvList+1) != CHAR_NULL + ; MasterEnvList += StrLen(MasterEnvList) + 1 + ){ + if (StrSize(MasterEnvList) > ItemSize) { + ItemSize = StrSize(MasterEnvList); + } + for (Temp = StrStr(OriginalCommandLine, MasterEnvList) + ; Temp != NULL + ; Temp = StrStr(Temp+1, MasterEnvList) + ){ + // + // we need a preceding and following % and if there is space no ^ preceding (if no space ignore) + // + if (*(Temp-1) == L'%' && *(Temp+StrLen(MasterEnvList)) == L'%' && + ((((Temp-OriginalCommandLine)>2) && *(Temp-2) != L'^') || ((Temp-OriginalCommandLine)<=2))) { + NewSize+=StrSize(EfiShellGetEnv(MasterEnvList)); + } + } + } + + // + // now do the replacements... + // + NewCommandLine1 = AllocateZeroPool (NewSize); + NewCommandLine2 = AllocateZeroPool(NewSize); + ItemTemp = AllocateZeroPool(ItemSize+(2*sizeof(CHAR16))); + if (NewCommandLine1 == NULL || NewCommandLine2 == NULL || ItemTemp == NULL) { + SHELL_FREE_NON_NULL(NewCommandLine1); + SHELL_FREE_NON_NULL(NewCommandLine2); + SHELL_FREE_NON_NULL(ItemTemp); + return (NULL); + } + CopyMem (NewCommandLine1, OriginalCommandLine, StrSize (OriginalCommandLine)); + + for (MasterEnvList = EfiShellGetEnv(NULL) + ; MasterEnvList != NULL && *MasterEnvList != CHAR_NULL + ; MasterEnvList += StrLen(MasterEnvList) + 1 + ){ + StrCpyS( ItemTemp, + ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)), + L"%" + ); + StrCatS( ItemTemp, + ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)), + MasterEnvList + ); + StrCatS( ItemTemp, + ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)), + L"%" + ); + ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, ItemTemp, EfiShellGetEnv(MasterEnvList), TRUE, FALSE); + StrCpyS(NewCommandLine1, NewSize/sizeof(CHAR16), NewCommandLine2); + } + if (CurrentScriptFile != NULL) { + for (AliasListNode = (ALIAS_LIST*)GetFirstNode(&CurrentScriptFile->SubstList) + ; !IsNull(&CurrentScriptFile->SubstList, &AliasListNode->Link) + ; AliasListNode = (ALIAS_LIST*)GetNextNode(&CurrentScriptFile->SubstList, &AliasListNode->Link) + ){ + ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, AliasListNode->Alias, AliasListNode->CommandString, TRUE, FALSE); + StrCpyS(NewCommandLine1, NewSize/sizeof(CHAR16), NewCommandLine2); + } + } + + // + // Remove non-existent environment variables + // + StripUnreplacedEnvironmentVariables(NewCommandLine1); + + // + // Now cleanup any straggler intentionally ignored "%" characters + // + ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, L"^%", L"%", TRUE, FALSE); + StrCpyS(NewCommandLine1, NewSize/sizeof(CHAR16), NewCommandLine2); + + FreePool(NewCommandLine2); + FreePool(ItemTemp); + + return (NewCommandLine1); +} + +/** + Internal function to run a command line with pipe usage. + + @param[in] CmdLine The pointer to the command line. + @param[in] StdIn The pointer to the Standard input. + @param[in] StdOut The pointer to the Standard output. + + @retval EFI_SUCCESS The split command is executed successfully. + @retval other Some error occurs when executing the split command. +**/ +EFI_STATUS +RunSplitCommand( + IN CONST CHAR16 *CmdLine, + IN SHELL_FILE_HANDLE StdIn, + IN SHELL_FILE_HANDLE StdOut + ) +{ + EFI_STATUS Status; + CHAR16 *NextCommandLine; + CHAR16 *OurCommandLine; + UINTN Size1; + UINTN Size2; + SPLIT_LIST *Split; + SHELL_FILE_HANDLE TempFileHandle; + BOOLEAN Unicode; + + ASSERT(StdOut == NULL); + + ASSERT(StrStr(CmdLine, L"|") != NULL); + + Status = EFI_SUCCESS; + NextCommandLine = NULL; + OurCommandLine = NULL; + Size1 = 0; + Size2 = 0; + + NextCommandLine = StrnCatGrow(&NextCommandLine, &Size1, StrStr(CmdLine, L"|")+1, 0); + OurCommandLine = StrnCatGrow(&OurCommandLine , &Size2, CmdLine , StrStr(CmdLine, L"|") - CmdLine); + + if (NextCommandLine == NULL || OurCommandLine == NULL) { + SHELL_FREE_NON_NULL(OurCommandLine); + SHELL_FREE_NON_NULL(NextCommandLine); + return (EFI_OUT_OF_RESOURCES); + } else if (StrStr(OurCommandLine, L"|") != NULL || Size1 == 0 || Size2 == 0) { + SHELL_FREE_NON_NULL(OurCommandLine); + SHELL_FREE_NON_NULL(NextCommandLine); + return (EFI_INVALID_PARAMETER); + } else if (NextCommandLine[0] == L'a' && + (NextCommandLine[1] == L' ' || NextCommandLine[1] == CHAR_NULL) + ){ + CopyMem(NextCommandLine, NextCommandLine+1, StrSize(NextCommandLine) - sizeof(NextCommandLine[0])); + while (NextCommandLine[0] == L' ') { + CopyMem(NextCommandLine, NextCommandLine+1, StrSize(NextCommandLine) - sizeof(NextCommandLine[0])); + } + if (NextCommandLine[0] == CHAR_NULL) { + SHELL_FREE_NON_NULL(OurCommandLine); + SHELL_FREE_NON_NULL(NextCommandLine); + return (EFI_INVALID_PARAMETER); + } + Unicode = FALSE; + } else { + Unicode = TRUE; + } + + + // + // make a SPLIT_LIST item and add to list + // + Split = AllocateZeroPool(sizeof(SPLIT_LIST)); + if (Split == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Split->SplitStdIn = StdIn; + Split->SplitStdOut = ConvertEfiFileProtocolToShellHandle(CreateFileInterfaceMem(Unicode), NULL); + ASSERT(Split->SplitStdOut != NULL); + InsertHeadList(&ShellInfoObject.SplitList.Link, &Split->Link); + + Status = RunCommand(OurCommandLine); + + // + // move the output from the first to the in to the second. + // + TempFileHandle = Split->SplitStdOut; + if (Split->SplitStdIn == StdIn) { + Split->SplitStdOut = NULL; + } else { + Split->SplitStdOut = Split->SplitStdIn; + } + Split->SplitStdIn = TempFileHandle; + ShellInfoObject.NewEfiShellProtocol->SetFilePosition (Split->SplitStdIn, 0); + + if (!EFI_ERROR(Status)) { + Status = RunCommand(NextCommandLine); + } + + // + // remove the top level from the ScriptList + // + ASSERT((SPLIT_LIST*)GetFirstNode(&ShellInfoObject.SplitList.Link) == Split); + RemoveEntryList(&Split->Link); + + // + // Note that the original StdIn is now the StdOut... + // + if (Split->SplitStdOut != NULL) { + ShellInfoObject.NewEfiShellProtocol->CloseFile (Split->SplitStdOut); + } + if (Split->SplitStdIn != NULL) { + ShellInfoObject.NewEfiShellProtocol->CloseFile (Split->SplitStdIn); + } + + FreePool(Split); + FreePool(NextCommandLine); + FreePool(OurCommandLine); + + return (Status); +} + +/** + Take the original command line, substitute any variables, free + the original string, return the modified copy. + + @param[in] CmdLine pointer to the command line to update. + + @retval EFI_SUCCESS the function was successful. + @retval EFI_OUT_OF_RESOURCES a memory allocation failed. +**/ +EFI_STATUS +ShellSubstituteVariables( + IN CHAR16 **CmdLine + ) +{ + CHAR16 *NewCmdLine; + NewCmdLine = ShellConvertVariables(*CmdLine); + SHELL_FREE_NON_NULL(*CmdLine); + if (NewCmdLine == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + *CmdLine = NewCmdLine; + return (EFI_SUCCESS); +} + +/** + Take the original command line, substitute any alias in the first group of space delimited characters, free + the original string, return the modified copy. + + @param[in] CmdLine pointer to the command line to update. + + @retval EFI_SUCCESS the function was successful. + @retval EFI_OUT_OF_RESOURCES a memory allocation failed. +**/ +EFI_STATUS +ShellSubstituteAliases( + IN CHAR16 **CmdLine + ) +{ + CHAR16 *NewCmdLine; + CHAR16 *CommandName; + EFI_STATUS Status; + UINTN PostAliasSize; + ASSERT(CmdLine != NULL); + ASSERT(*CmdLine!= NULL); + + + CommandName = NULL; + if (StrStr((*CmdLine), L" ") == NULL){ + StrnCatGrow(&CommandName, NULL, (*CmdLine), 0); + } else { + StrnCatGrow(&CommandName, NULL, (*CmdLine), StrStr((*CmdLine), L" ") - (*CmdLine)); + } + + // + // This cannot happen 'inline' since the CmdLine can need extra space. + // + NewCmdLine = NULL; + if (!ShellCommandIsCommandOnList(CommandName)) { + // + // Convert via alias + // + Status = ShellConvertAlias(&CommandName); + if (EFI_ERROR(Status)){ + return (Status); + } + PostAliasSize = 0; + NewCmdLine = StrnCatGrow(&NewCmdLine, &PostAliasSize, CommandName, 0); + if (NewCmdLine == NULL) { + SHELL_FREE_NON_NULL(CommandName); + SHELL_FREE_NON_NULL(*CmdLine); + return (EFI_OUT_OF_RESOURCES); + } + NewCmdLine = StrnCatGrow(&NewCmdLine, &PostAliasSize, StrStr((*CmdLine), L" "), 0); + if (NewCmdLine == NULL) { + SHELL_FREE_NON_NULL(CommandName); + SHELL_FREE_NON_NULL(*CmdLine); + return (EFI_OUT_OF_RESOURCES); + } + } else { + NewCmdLine = StrnCatGrow(&NewCmdLine, NULL, (*CmdLine), 0); + } + + SHELL_FREE_NON_NULL(*CmdLine); + SHELL_FREE_NON_NULL(CommandName); + + // + // re-assign the passed in double pointer to point to our newly allocated buffer + // + *CmdLine = NewCmdLine; + + return (EFI_SUCCESS); +} + +/** + Takes the Argv[0] part of the command line and determine the meaning of it. + + @param[in] CmdName pointer to the command line to update. + + @retval Internal_Command The name is an internal command. + @retval File_Sys_Change the name is a file system change. + @retval Script_File_Name the name is a NSH script file. + @retval Unknown_Invalid the name is unknown. + @retval Efi_Application the name is an application (.EFI). +**/ +SHELL_OPERATION_TYPES +GetOperationType( + IN CONST CHAR16 *CmdName + ) +{ + CHAR16* FileWithPath; + CONST CHAR16* TempLocation; + CONST CHAR16* TempLocation2; + + FileWithPath = NULL; + // + // test for an internal command. + // + if (ShellCommandIsCommandOnList(CmdName)) { + return (Internal_Command); + } + + // + // Test for file system change request. anything ending with first : and cant have spaces. + // + if (CmdName[(StrLen(CmdName)-1)] == L':') { + if ( StrStr(CmdName, L" ") != NULL + || StrLen(StrStr(CmdName, L":")) > 1 + ) { + return (Unknown_Invalid); + } + return (File_Sys_Change); + } + + // + // Test for a file + // + if ((FileWithPath = ShellFindFilePathEx(CmdName, mExecutableExtensions)) != NULL) { + // + // See if that file has a script file extension + // + if (StrLen(FileWithPath) > 4) { + TempLocation = FileWithPath+StrLen(FileWithPath)-4; + TempLocation2 = mScriptExtension; + if (StringNoCaseCompare((VOID*)(&TempLocation), (VOID*)(&TempLocation2)) == 0) { + SHELL_FREE_NON_NULL(FileWithPath); + return (Script_File_Name); + } + } + + // + // Was a file, but not a script. we treat this as an application. + // + SHELL_FREE_NON_NULL(FileWithPath); + return (Efi_Application); + } + + SHELL_FREE_NON_NULL(FileWithPath); + // + // No clue what this is... return invalid flag... + // + return (Unknown_Invalid); +} + +/** + Determine if the first item in a command line is valid. + + @param[in] CmdLine The command line to parse. + + @retval EFI_SUCCESS The item is valid. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_NOT_FOUND The operation type is unknown or invalid. +**/ +EFI_STATUS +IsValidSplit( + IN CONST CHAR16 *CmdLine + ) +{ + CHAR16 *Temp; + CHAR16 *FirstParameter; + CHAR16 *TempWalker; + EFI_STATUS Status; + + Temp = NULL; + + Temp = StrnCatGrow(&Temp, NULL, CmdLine, 0); + if (Temp == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + FirstParameter = StrStr(Temp, L"|"); + if (FirstParameter != NULL) { + *FirstParameter = CHAR_NULL; + } + + FirstParameter = NULL; + + // + // Process the command line + // + Status = ProcessCommandLineToFinal(&Temp); + + if (!EFI_ERROR(Status)) { + FirstParameter = AllocateZeroPool(StrSize(CmdLine)); + if (FirstParameter == NULL) { + SHELL_FREE_NON_NULL(Temp); + return (EFI_OUT_OF_RESOURCES); + } + TempWalker = (CHAR16*)Temp; + if (!EFI_ERROR(GetNextParameter(&TempWalker, &FirstParameter, StrSize(CmdLine), TRUE))) { + if (GetOperationType(FirstParameter) == Unknown_Invalid) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, FirstParameter); + SetLastError(SHELL_NOT_FOUND); + Status = EFI_NOT_FOUND; + } + } + } + + SHELL_FREE_NON_NULL(Temp); + SHELL_FREE_NON_NULL(FirstParameter); + return Status; +} + +/** + Determine if a command line contains with a split contains only valid commands. + + @param[in] CmdLine The command line to parse. + + @retval EFI_SUCCESS CmdLine has only valid commands, application, or has no split. + @retval EFI_ABORTED CmdLine has at least one invalid command or application. +**/ +EFI_STATUS +VerifySplit( + IN CONST CHAR16 *CmdLine + ) +{ + CONST CHAR16 *TempSpot; + EFI_STATUS Status; + + // + // If this was the only item, then get out + // + if (!ContainsSplit(CmdLine)) { + return (EFI_SUCCESS); + } + + // + // Verify up to the pipe or end character + // + Status = IsValidSplit(CmdLine); + if (EFI_ERROR(Status)) { + return (Status); + } + + // + // recurse to verify the next item + // + TempSpot = FindFirstCharacter(CmdLine, L"|", L'^') + 1; + if (*TempSpot == L'a' && + (*(TempSpot + 1) == L' ' || *(TempSpot + 1) == CHAR_NULL) + ) { + // If it's an ASCII pipe '|a' + TempSpot += 1; + } + + return (VerifySplit(TempSpot)); +} + +/** + Process a split based operation. + + @param[in] CmdLine pointer to the command line to process + + @retval EFI_SUCCESS The operation was successful + @return an error occurred. +**/ +EFI_STATUS +ProcessNewSplitCommandLine( + IN CONST CHAR16 *CmdLine + ) +{ + SPLIT_LIST *Split; + EFI_STATUS Status; + + Status = VerifySplit(CmdLine); + if (EFI_ERROR(Status)) { + return (Status); + } + + Split = NULL; + + // + // are we in an existing split??? + // + if (!IsListEmpty(&ShellInfoObject.SplitList.Link)) { + Split = (SPLIT_LIST*)GetFirstNode(&ShellInfoObject.SplitList.Link); + } + + if (Split == NULL) { + Status = RunSplitCommand(CmdLine, NULL, NULL); + } else { + Status = RunSplitCommand(CmdLine, Split->SplitStdIn, Split->SplitStdOut); + } + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_INVALID_SPLIT), ShellInfoObject.HiiHandle, CmdLine); + } + return (Status); +} + +/** + Handle a request to change the current file system. + + @param[in] CmdLine The passed in command line. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ChangeMappedDrive( + IN CONST CHAR16 *CmdLine + ) +{ + EFI_STATUS Status; + Status = EFI_SUCCESS; + + // + // make sure we are the right operation + // + ASSERT(CmdLine[(StrLen(CmdLine)-1)] == L':' && StrStr(CmdLine, L" ") == NULL); + + // + // Call the protocol API to do the work + // + Status = ShellInfoObject.NewEfiShellProtocol->SetCurDir(NULL, CmdLine); + + // + // Report any errors + // + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_INVALID_MAPPING), ShellInfoObject.HiiHandle, CmdLine); + } + + return (Status); +} + +/** + Reprocess the command line to direct all -? to the help command. + + if found, will add "help" as argv[0], and move the rest later. + + @param[in,out] CmdLine pointer to the command line to update +**/ +EFI_STATUS +DoHelpUpdate( + IN OUT CHAR16 **CmdLine + ) +{ + CHAR16 *CurrentParameter; + CHAR16 *Walker; + CHAR16 *NewCommandLine; + EFI_STATUS Status; + UINTN NewCmdLineSize; + + Status = EFI_SUCCESS; + + CurrentParameter = AllocateZeroPool(StrSize(*CmdLine)); + if (CurrentParameter == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + Walker = *CmdLine; + while(Walker != NULL && *Walker != CHAR_NULL) { + if (!EFI_ERROR(GetNextParameter(&Walker, &CurrentParameter, StrSize(*CmdLine), TRUE))) { + if (StrStr(CurrentParameter, L"-?") == CurrentParameter) { + CurrentParameter[0] = L' '; + CurrentParameter[1] = L' '; + NewCmdLineSize = StrSize(L"help ") + StrSize(*CmdLine); + NewCommandLine = AllocateZeroPool(NewCmdLineSize); + if (NewCommandLine == NULL) { + Status = EFI_OUT_OF_RESOURCES; + break; + } + + // + // We know the space is sufficient since we just calculated it. + // + StrnCpyS(NewCommandLine, NewCmdLineSize/sizeof(CHAR16), L"help ", 5); + StrnCatS(NewCommandLine, NewCmdLineSize/sizeof(CHAR16), *CmdLine, StrLen(*CmdLine)); + SHELL_FREE_NON_NULL(*CmdLine); + *CmdLine = NewCommandLine; + break; + } + } + } + + SHELL_FREE_NON_NULL(CurrentParameter); + + return (Status); +} + +/** + Function to update the shell variable "lasterror". + + @param[in] ErrorCode the error code to put into lasterror. +**/ +EFI_STATUS +SetLastError( + IN CONST SHELL_STATUS ErrorCode + ) +{ + CHAR16 LeString[19]; + if (sizeof(EFI_STATUS) == sizeof(UINT64)) { + UnicodeSPrint(LeString, sizeof(LeString), L"0x%Lx", ErrorCode); + } else { + UnicodeSPrint(LeString, sizeof(LeString), L"0x%x", ErrorCode); + } + DEBUG_CODE(InternalEfiShellSetEnv(L"debuglasterror", LeString, TRUE);); + InternalEfiShellSetEnv(L"lasterror", LeString, TRUE); + + return (EFI_SUCCESS); +} + +/** + Converts the command line to its post-processed form. this replaces variables and alias' per UEFI Shell spec. + + @param[in,out] CmdLine pointer to the command line to update + + @retval EFI_SUCCESS The operation was successful + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @return some other error occurred +**/ +EFI_STATUS +ProcessCommandLineToFinal( + IN OUT CHAR16 **CmdLine + ) +{ + EFI_STATUS Status; + TrimSpaces(CmdLine); + + Status = ShellSubstituteAliases(CmdLine); + if (EFI_ERROR(Status)) { + return (Status); + } + + TrimSpaces(CmdLine); + + Status = ShellSubstituteVariables(CmdLine); + if (EFI_ERROR(Status)) { + return (Status); + } + ASSERT (*CmdLine != NULL); + + TrimSpaces(CmdLine); + + // + // update for help parsing + // + if (StrStr(*CmdLine, L"?") != NULL) { + // + // This may do nothing if the ? does not indicate help. + // Save all the details for in the API below. + // + Status = DoHelpUpdate(CmdLine); + } + + TrimSpaces(CmdLine); + + return (EFI_SUCCESS); +} + +/** + Run an internal shell command. + + This API will update the shell's environment since these commands are libraries. + + @param[in] CmdLine the command line to run. + @param[in] FirstParameter the first parameter on the command line + @param[in] ParamProtocol the shell parameters protocol pointer + @param[out] CommandStatus the status from the command line. + + @retval EFI_SUCCESS The command was completed. + @retval EFI_ABORTED The command's operation was aborted. +**/ +EFI_STATUS +RunInternalCommand( + IN CONST CHAR16 *CmdLine, + IN CHAR16 *FirstParameter, + IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol, + OUT EFI_STATUS *CommandStatus +) +{ + EFI_STATUS Status; + UINTN Argc; + CHAR16 **Argv; + SHELL_STATUS CommandReturnedStatus; + BOOLEAN LastError; + CHAR16 *Walker; + CHAR16 *NewCmdLine; + + NewCmdLine = AllocateCopyPool (StrSize (CmdLine), CmdLine); + if (NewCmdLine == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + for (Walker = NewCmdLine; Walker != NULL && *Walker != CHAR_NULL ; Walker++) { + if (*Walker == L'^' && *(Walker+1) == L'#') { + CopyMem(Walker, Walker+1, StrSize(Walker) - sizeof(Walker[0])); + } + } + + // + // get the argc and argv updated for internal commands + // + Status = UpdateArgcArgv(ParamProtocol, NewCmdLine, Internal_Command, &Argv, &Argc); + if (!EFI_ERROR(Status)) { + // + // Run the internal command. + // + Status = ShellCommandRunCommandHandler(FirstParameter, &CommandReturnedStatus, &LastError); + + if (!EFI_ERROR(Status)) { + if (CommandStatus != NULL) { + if (CommandReturnedStatus != SHELL_SUCCESS) { + *CommandStatus = (EFI_STATUS)(CommandReturnedStatus | MAX_BIT); + } else { + *CommandStatus = EFI_SUCCESS; + } + } + + // + // Update last error status. + // some commands do not update last error. + // + if (LastError) { + SetLastError(CommandReturnedStatus); + } + + // + // Pass thru the exitcode from the app. + // + if (ShellCommandGetExit()) { + // + // An Exit was requested ("exit" command), pass its value up. + // + Status = CommandReturnedStatus; + } else if (CommandReturnedStatus != SHELL_SUCCESS && IsScriptOnlyCommand(FirstParameter)) { + // + // Always abort when a script only command fails for any reason + // + Status = EFI_ABORTED; + } else if (ShellCommandGetCurrentScriptFile() != NULL && CommandReturnedStatus == SHELL_ABORTED) { + // + // Abort when in a script and a command aborted + // + Status = EFI_ABORTED; + } + } + } + + // + // This is guaranteed to be called after UpdateArgcArgv no matter what else happened. + // This is safe even if the update API failed. In this case, it may be a no-op. + // + RestoreArgcArgv(ParamProtocol, &Argv, &Argc); + + // + // If a script is running and the command is not a script only command, then + // change return value to success so the script won't halt (unless aborted). + // + // Script only commands have to be able halt the script since the script will + // not operate if they are failing. + // + if ( ShellCommandGetCurrentScriptFile() != NULL + && !IsScriptOnlyCommand(FirstParameter) + && Status != EFI_ABORTED + ) { + Status = EFI_SUCCESS; + } + + FreePool (NewCmdLine); + return (Status); +} + +/** + Function to run the command or file. + + @param[in] Type the type of operation being run. + @param[in] CmdLine the command line to run. + @param[in] FirstParameter the first parameter on the command line + @param[in] ParamProtocol the shell parameters protocol pointer + @param[out] CommandStatus the status from the command line. + + @retval EFI_SUCCESS The command was completed. + @retval EFI_ABORTED The command's operation was aborted. +**/ +EFI_STATUS +RunCommandOrFile( + IN SHELL_OPERATION_TYPES Type, + IN CONST CHAR16 *CmdLine, + IN CHAR16 *FirstParameter, + IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol, + OUT EFI_STATUS *CommandStatus +) +{ + EFI_STATUS Status; + EFI_STATUS StartStatus; + CHAR16 *CommandWithPath; + CHAR16 *FullCommandWithPath; + EFI_DEVICE_PATH_PROTOCOL *DevPath; + SHELL_STATUS CalleeExitStatus; + + Status = EFI_SUCCESS; + CommandWithPath = NULL; + DevPath = NULL; + CalleeExitStatus = SHELL_INVALID_PARAMETER; + + switch (Type) { + case Internal_Command: + Status = RunInternalCommand(CmdLine, FirstParameter, ParamProtocol, CommandStatus); + break; + case Script_File_Name: + case Efi_Application: + // + // Process a fully qualified path + // + if (StrStr(FirstParameter, L":") != NULL) { + ASSERT (CommandWithPath == NULL); + if (ShellIsFile(FirstParameter) == EFI_SUCCESS) { + CommandWithPath = StrnCatGrow(&CommandWithPath, NULL, FirstParameter, 0); + } + } + + // + // Process a relative path and also check in the path environment variable + // + if (CommandWithPath == NULL) { + CommandWithPath = ShellFindFilePathEx(FirstParameter, mExecutableExtensions); + } + + // + // This should be impossible now. + // + ASSERT(CommandWithPath != NULL); + + // + // Make sure that path is not just a directory (or not found) + // + if (!EFI_ERROR(ShellIsDirectory(CommandWithPath))) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, FirstParameter); + SetLastError(SHELL_NOT_FOUND); + } + switch (Type) { + case Script_File_Name: + FullCommandWithPath = FullyQualifyPath(CommandWithPath); + if (FullCommandWithPath == NULL) { + Status = RunScriptFile (CommandWithPath, NULL, CmdLine, ParamProtocol); + } else { + Status = RunScriptFile (FullCommandWithPath, NULL, CmdLine, ParamProtocol); + FreePool(FullCommandWithPath); + } + break; + case Efi_Application: + // + // Get the device path of the application image + // + DevPath = ShellInfoObject.NewEfiShellProtocol->GetDevicePathFromFilePath(CommandWithPath); + if (DevPath == NULL){ + Status = EFI_OUT_OF_RESOURCES; + break; + } + + // + // Execute the device path + // + Status = InternalShellExecuteDevicePath( + &gImageHandle, + DevPath, + CmdLine, + NULL, + &StartStatus + ); + + SHELL_FREE_NON_NULL(DevPath); + + if(EFI_ERROR (Status)) { + CalleeExitStatus = (SHELL_STATUS) (Status & (~MAX_BIT)); + } else { + CalleeExitStatus = (SHELL_STATUS) StartStatus; + } + + if (CommandStatus != NULL) { + *CommandStatus = CalleeExitStatus; + } + + // + // Update last error status. + // + // Status is an EFI_STATUS. Clear top bit to convert to SHELL_STATUS + SetLastError(CalleeExitStatus); + break; + default: + // + // Do nothing. + // + break; + } + break; + default: + // + // Do nothing. + // + break; + } + + SHELL_FREE_NON_NULL(CommandWithPath); + + return (Status); +} + +/** + Function to setup StdIn, StdErr, StdOut, and then run the command or file. + + @param[in] Type the type of operation being run. + @param[in] CmdLine the command line to run. + @param[in] FirstParameter the first parameter on the command line. + @param[in] ParamProtocol the shell parameters protocol pointer + @param[out] CommandStatus the status from the command line. + + @retval EFI_SUCCESS The command was completed. + @retval EFI_ABORTED The command's operation was aborted. +**/ +EFI_STATUS +SetupAndRunCommandOrFile( + IN SHELL_OPERATION_TYPES Type, + IN CHAR16 *CmdLine, + IN CHAR16 *FirstParameter, + IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol, + OUT EFI_STATUS *CommandStatus +) +{ + EFI_STATUS Status; + SHELL_FILE_HANDLE OriginalStdIn; + SHELL_FILE_HANDLE OriginalStdOut; + SHELL_FILE_HANDLE OriginalStdErr; + SYSTEM_TABLE_INFO OriginalSystemTableInfo; + CONST SCRIPT_FILE *ConstScriptFile; + + // + // Update the StdIn, StdOut, and StdErr for redirection to environment variables, files, etc... unicode and ASCII + // + Status = UpdateStdInStdOutStdErr(ParamProtocol, CmdLine, &OriginalStdIn, &OriginalStdOut, &OriginalStdErr, &OriginalSystemTableInfo); + + // + // The StdIn, StdOut, and StdErr are set up. + // Now run the command, script, or application + // + if (!EFI_ERROR(Status)) { + TrimSpaces(&CmdLine); + Status = RunCommandOrFile(Type, CmdLine, FirstParameter, ParamProtocol, CommandStatus); + } + + // + // Now print errors + // + if (EFI_ERROR(Status)) { + ConstScriptFile = ShellCommandGetCurrentScriptFile(); + if (ConstScriptFile == NULL || ConstScriptFile->CurrentCommand == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_ERROR), ShellInfoObject.HiiHandle, (VOID*)(Status)); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_ERROR_SCRIPT), ShellInfoObject.HiiHandle, (VOID*)(Status), ConstScriptFile->CurrentCommand->Line); + } + } + + // + // put back the original StdIn, StdOut, and StdErr + // + RestoreStdInStdOutStdErr(ParamProtocol, &OriginalStdIn, &OriginalStdOut, &OriginalStdErr, &OriginalSystemTableInfo); + + return (Status); +} + +/** + Function will process and run a command line. + + This will determine if the command line represents an internal shell + command or dispatch an external application. + + @param[in] CmdLine The command line to parse. + @param[out] CommandStatus The status from the command line. + + @retval EFI_SUCCESS The command was completed. + @retval EFI_ABORTED The command's operation was aborted. +**/ +EFI_STATUS +RunShellCommand( + IN CONST CHAR16 *CmdLine, + OUT EFI_STATUS *CommandStatus + ) +{ + EFI_STATUS Status; + CHAR16 *CleanOriginal; + CHAR16 *FirstParameter; + CHAR16 *TempWalker; + SHELL_OPERATION_TYPES Type; + CONST CHAR16 *CurDir; + + ASSERT(CmdLine != NULL); + if (StrLen(CmdLine) == 0) { + return (EFI_SUCCESS); + } + + Status = EFI_SUCCESS; + CleanOriginal = NULL; + + CleanOriginal = StrnCatGrow(&CleanOriginal, NULL, CmdLine, 0); + if (CleanOriginal == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + TrimSpaces(&CleanOriginal); + + // + // NULL out comments (leveraged from RunScriptFileHandle() ). + // The # character on a line is used to denote that all characters on the same line + // and to the right of the # are to be ignored by the shell. + // Afterwards, again remove spaces, in case any were between the last command-parameter and '#'. + // + for (TempWalker = CleanOriginal; TempWalker != NULL && *TempWalker != CHAR_NULL; TempWalker++) { + if (*TempWalker == L'^') { + if (*(TempWalker + 1) == L'#') { + TempWalker++; + } + } else if (*TempWalker == L'#') { + *TempWalker = CHAR_NULL; + } + } + + TrimSpaces(&CleanOriginal); + + // + // Handle case that passed in command line is just 1 or more " " characters. + // + if (StrLen (CleanOriginal) == 0) { + SHELL_FREE_NON_NULL(CleanOriginal); + return (EFI_SUCCESS); + } + + Status = ProcessCommandLineToFinal(&CleanOriginal); + if (EFI_ERROR(Status)) { + SHELL_FREE_NON_NULL(CleanOriginal); + return (Status); + } + + // + // We don't do normal processing with a split command line (output from one command input to another) + // + if (ContainsSplit(CleanOriginal)) { + Status = ProcessNewSplitCommandLine(CleanOriginal); + SHELL_FREE_NON_NULL(CleanOriginal); + return (Status); + } + + // + // We need the first parameter information so we can determine the operation type + // + FirstParameter = AllocateZeroPool(StrSize(CleanOriginal)); + if (FirstParameter == NULL) { + SHELL_FREE_NON_NULL(CleanOriginal); + return (EFI_OUT_OF_RESOURCES); + } + TempWalker = CleanOriginal; + if (!EFI_ERROR(GetNextParameter(&TempWalker, &FirstParameter, StrSize(CleanOriginal), TRUE))) { + // + // Depending on the first parameter we change the behavior + // + switch (Type = GetOperationType(FirstParameter)) { + case File_Sys_Change: + Status = ChangeMappedDrive (FirstParameter); + break; + case Internal_Command: + case Script_File_Name: + case Efi_Application: + Status = SetupAndRunCommandOrFile(Type, CleanOriginal, FirstParameter, ShellInfoObject.NewShellParametersProtocol, CommandStatus); + break; + default: + // + // Whatever was typed, it was invalid. + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, FirstParameter); + SetLastError(SHELL_NOT_FOUND); + break; + } + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, FirstParameter); + SetLastError(SHELL_NOT_FOUND); + } + // + // Check whether the current file system still exists. If not exist, we need update "cwd" and gShellCurMapping. + // + CurDir = EfiShellGetCurDir (NULL); + if (CurDir != NULL) { + if (EFI_ERROR(ShellFileExists (CurDir))) { + // + // EfiShellSetCurDir() cannot set current directory to NULL. + // EfiShellSetEnv() is not allowed to set the "cwd" variable. + // Only InternalEfiShellSetEnv () is allowed setting the "cwd" variable. + // + InternalEfiShellSetEnv (L"cwd", NULL, TRUE); + gShellCurMapping = NULL; + } + } + + SHELL_FREE_NON_NULL(CleanOriginal); + SHELL_FREE_NON_NULL(FirstParameter); + + return (Status); +} + +/** + Function will process and run a command line. + + This will determine if the command line represents an internal shell + command or dispatch an external application. + + @param[in] CmdLine The command line to parse. + + @retval EFI_SUCCESS The command was completed. + @retval EFI_ABORTED The command's operation was aborted. +**/ +EFI_STATUS +RunCommand( + IN CONST CHAR16 *CmdLine + ) +{ + return (RunShellCommand(CmdLine, NULL)); +} + +/** + Function to process a NSH script file via SHELL_FILE_HANDLE. + + @param[in] Handle The handle to the already opened file. + @param[in] Name The name of the script file. + + @retval EFI_SUCCESS the script completed successfully +**/ +EFI_STATUS +RunScriptFileHandle ( + IN SHELL_FILE_HANDLE Handle, + IN CONST CHAR16 *Name + ) +{ + EFI_STATUS Status; + SCRIPT_FILE *NewScriptFile; + UINTN LoopVar; + UINTN PrintBuffSize; + CHAR16 *CommandLine; + CHAR16 *CommandLine2; + CHAR16 *CommandLine3; + SCRIPT_COMMAND_LIST *LastCommand; + BOOLEAN Ascii; + BOOLEAN PreScriptEchoState; + BOOLEAN PreCommandEchoState; + CONST CHAR16 *CurDir; + UINTN LineCount; + CHAR16 LeString[50]; + LIST_ENTRY OldBufferList; + + ASSERT(!ShellCommandGetScriptExit()); + + PreScriptEchoState = ShellCommandGetEchoState(); + PrintBuffSize = PcdGet16(PcdShellPrintBufferSize); + + NewScriptFile = (SCRIPT_FILE*)AllocateZeroPool(sizeof(SCRIPT_FILE)); + if (NewScriptFile == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + // + // Set up the name + // + ASSERT(NewScriptFile->ScriptName == NULL); + NewScriptFile->ScriptName = StrnCatGrow(&NewScriptFile->ScriptName, NULL, Name, 0); + if (NewScriptFile->ScriptName == NULL) { + DeleteScriptFileStruct(NewScriptFile); + return (EFI_OUT_OF_RESOURCES); + } + + // + // Save the parameters (used to replace %0 to %9 later on) + // + NewScriptFile->Argc = ShellInfoObject.NewShellParametersProtocol->Argc; + if (NewScriptFile->Argc != 0) { + NewScriptFile->Argv = (CHAR16**)AllocateZeroPool(NewScriptFile->Argc * sizeof(CHAR16*)); + if (NewScriptFile->Argv == NULL) { + DeleteScriptFileStruct(NewScriptFile); + return (EFI_OUT_OF_RESOURCES); + } + // + // Put the full path of the script file into Argv[0] as required by section + // 3.6.2 of version 2.2 of the shell specification. + // + NewScriptFile->Argv[0] = StrnCatGrow(&NewScriptFile->Argv[0], NULL, NewScriptFile->ScriptName, 0); + for (LoopVar = 1 ; LoopVar < 10 && LoopVar < NewScriptFile->Argc; LoopVar++) { + ASSERT(NewScriptFile->Argv[LoopVar] == NULL); + NewScriptFile->Argv[LoopVar] = StrnCatGrow(&NewScriptFile->Argv[LoopVar], NULL, ShellInfoObject.NewShellParametersProtocol->Argv[LoopVar], 0); + if (NewScriptFile->Argv[LoopVar] == NULL) { + DeleteScriptFileStruct(NewScriptFile); + return (EFI_OUT_OF_RESOURCES); + } + } + } else { + NewScriptFile->Argv = NULL; + } + + InitializeListHead(&NewScriptFile->CommandList); + InitializeListHead(&NewScriptFile->SubstList); + + // + // Now build the list of all script commands. + // + LineCount = 0; + while(!ShellFileHandleEof(Handle)) { + CommandLine = ShellFileHandleReturnLine(Handle, &Ascii); + LineCount++; + if (CommandLine == NULL || StrLen(CommandLine) == 0 || CommandLine[0] == '#') { + SHELL_FREE_NON_NULL(CommandLine); + continue; + } + NewScriptFile->CurrentCommand = AllocateZeroPool(sizeof(SCRIPT_COMMAND_LIST)); + if (NewScriptFile->CurrentCommand == NULL) { + SHELL_FREE_NON_NULL(CommandLine); + DeleteScriptFileStruct(NewScriptFile); + return (EFI_OUT_OF_RESOURCES); + } + + NewScriptFile->CurrentCommand->Cl = CommandLine; + NewScriptFile->CurrentCommand->Data = NULL; + NewScriptFile->CurrentCommand->Line = LineCount; + + InsertTailList(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link); + } + + // + // Add this as the topmost script file + // + ShellCommandSetNewScript (NewScriptFile); + + // + // Now enumerate through the commands and run each one. + // + CommandLine = AllocateZeroPool(PrintBuffSize); + if (CommandLine == NULL) { + DeleteScriptFileStruct(NewScriptFile); + return (EFI_OUT_OF_RESOURCES); + } + CommandLine2 = AllocateZeroPool(PrintBuffSize); + if (CommandLine2 == NULL) { + FreePool(CommandLine); + DeleteScriptFileStruct(NewScriptFile); + return (EFI_OUT_OF_RESOURCES); + } + + for ( NewScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetFirstNode(&NewScriptFile->CommandList) + ; !IsNull(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link) + ; // conditional increment in the body of the loop + ){ + ASSERT(CommandLine2 != NULL); + StrnCpyS( CommandLine2, + PrintBuffSize/sizeof(CHAR16), + NewScriptFile->CurrentCommand->Cl, + PrintBuffSize/sizeof(CHAR16) - 1 + ); + + SaveBufferList(&OldBufferList); + + // + // NULL out comments + // + for (CommandLine3 = CommandLine2 ; CommandLine3 != NULL && *CommandLine3 != CHAR_NULL ; CommandLine3++) { + if (*CommandLine3 == L'^') { + if ( *(CommandLine3+1) == L':') { + CopyMem(CommandLine3, CommandLine3+1, StrSize(CommandLine3) - sizeof(CommandLine3[0])); + } else if (*(CommandLine3+1) == L'#') { + CommandLine3++; + } + } else if (*CommandLine3 == L'#') { + *CommandLine3 = CHAR_NULL; + } + } + + if (CommandLine2 != NULL && StrLen(CommandLine2) >= 1) { + // + // Due to variability in starting the find and replace action we need to have both buffers the same. + // + StrnCpyS( CommandLine, + PrintBuffSize/sizeof(CHAR16), + CommandLine2, + PrintBuffSize/sizeof(CHAR16) - 1 + ); + + // + // Remove the %0 to %9 from the command line (if we have some arguments) + // + if (NewScriptFile->Argv != NULL) { + switch (NewScriptFile->Argc) { + default: + Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PrintBuffSize, L"%9", NewScriptFile->Argv[9], FALSE, FALSE); + ASSERT_EFI_ERROR(Status); + case 9: + Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PrintBuffSize, L"%8", NewScriptFile->Argv[8], FALSE, FALSE); + ASSERT_EFI_ERROR(Status); + case 8: + Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PrintBuffSize, L"%7", NewScriptFile->Argv[7], FALSE, FALSE); + ASSERT_EFI_ERROR(Status); + case 7: + Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PrintBuffSize, L"%6", NewScriptFile->Argv[6], FALSE, FALSE); + ASSERT_EFI_ERROR(Status); + case 6: + Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PrintBuffSize, L"%5", NewScriptFile->Argv[5], FALSE, FALSE); + ASSERT_EFI_ERROR(Status); + case 5: + Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PrintBuffSize, L"%4", NewScriptFile->Argv[4], FALSE, FALSE); + ASSERT_EFI_ERROR(Status); + case 4: + Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PrintBuffSize, L"%3", NewScriptFile->Argv[3], FALSE, FALSE); + ASSERT_EFI_ERROR(Status); + case 3: + Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PrintBuffSize, L"%2", NewScriptFile->Argv[2], FALSE, FALSE); + ASSERT_EFI_ERROR(Status); + case 2: + Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PrintBuffSize, L"%1", NewScriptFile->Argv[1], FALSE, FALSE); + ASSERT_EFI_ERROR(Status); + case 1: + Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PrintBuffSize, L"%0", NewScriptFile->Argv[0], FALSE, FALSE); + ASSERT_EFI_ERROR(Status); + break; + case 0: + break; + } + } + Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PrintBuffSize, L"%1", L"\"\"", FALSE, FALSE); + Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PrintBuffSize, L"%2", L"\"\"", FALSE, FALSE); + Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PrintBuffSize, L"%3", L"\"\"", FALSE, FALSE); + Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PrintBuffSize, L"%4", L"\"\"", FALSE, FALSE); + Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PrintBuffSize, L"%5", L"\"\"", FALSE, FALSE); + Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PrintBuffSize, L"%6", L"\"\"", FALSE, FALSE); + Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PrintBuffSize, L"%7", L"\"\"", FALSE, FALSE); + Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PrintBuffSize, L"%8", L"\"\"", FALSE, FALSE); + Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PrintBuffSize, L"%9", L"\"\"", FALSE, FALSE); + + StrnCpyS( CommandLine2, + PrintBuffSize/sizeof(CHAR16), + CommandLine, + PrintBuffSize/sizeof(CHAR16) - 1 + ); + + LastCommand = NewScriptFile->CurrentCommand; + + for (CommandLine3 = CommandLine2 ; CommandLine3[0] == L' ' ; CommandLine3++); + + if (CommandLine3 != NULL && CommandLine3[0] == L':' ) { + // + // This line is a goto target / label + // + } else { + if (CommandLine3 != NULL && StrLen(CommandLine3) > 0) { + if (CommandLine3[0] == L'@') { + // + // We need to save the current echo state + // and disable echo for just this command. + // + PreCommandEchoState = ShellCommandGetEchoState(); + ShellCommandSetEchoState(FALSE); + Status = RunCommand(CommandLine3+1); + + // + // If command was "@echo -off" or "@echo -on" then don't restore echo state + // + if (StrCmp (L"@echo -off", CommandLine3) != 0 && + StrCmp (L"@echo -on", CommandLine3) != 0) { + // + // Now restore the pre-'@' echo state. + // + ShellCommandSetEchoState(PreCommandEchoState); + } + } else { + if (ShellCommandGetEchoState()) { + CurDir = ShellInfoObject.NewEfiShellProtocol->GetEnv(L"cwd"); + if (CurDir != NULL && StrLen(CurDir) > 1) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_CURDIR), ShellInfoObject.HiiHandle, CurDir); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_SHELL), ShellInfoObject.HiiHandle); + } + ShellPrintEx(-1, -1, L"%s\r\n", CommandLine2); + } + Status = RunCommand(CommandLine3); + } + } + + if (ShellCommandGetScriptExit()) { + // + // ShellCommandGetExitCode() always returns a UINT64 + // + UnicodeSPrint(LeString, sizeof(LeString), L"0x%Lx", ShellCommandGetExitCode()); + DEBUG_CODE(InternalEfiShellSetEnv(L"debuglasterror", LeString, TRUE);); + InternalEfiShellSetEnv(L"lasterror", LeString, TRUE); + + ShellCommandRegisterExit(FALSE, 0); + Status = EFI_SUCCESS; + RestoreBufferList(&OldBufferList); + break; + } + if (ShellGetExecutionBreakFlag()) { + RestoreBufferList(&OldBufferList); + break; + } + if (EFI_ERROR(Status)) { + RestoreBufferList(&OldBufferList); + break; + } + if (ShellCommandGetExit()) { + RestoreBufferList(&OldBufferList); + break; + } + } + // + // If that commend did not update the CurrentCommand then we need to advance it... + // + if (LastCommand == NewScriptFile->CurrentCommand) { + NewScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetNextNode(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link); + if (!IsNull(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link)) { + NewScriptFile->CurrentCommand->Reset = TRUE; + } + } + } else { + NewScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetNextNode(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link); + if (!IsNull(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link)) { + NewScriptFile->CurrentCommand->Reset = TRUE; + } + } + RestoreBufferList(&OldBufferList); + } + + + FreePool(CommandLine); + FreePool(CommandLine2); + ShellCommandSetNewScript (NULL); + + // + // Only if this was the last script reset the state. + // + if (ShellCommandGetCurrentScriptFile()==NULL) { + ShellCommandSetEchoState(PreScriptEchoState); + } + return (EFI_SUCCESS); +} + +/** + Function to process a NSH script file. + + @param[in] ScriptPath Pointer to the script file name (including file system path). + @param[in] Handle the handle of the script file already opened. + @param[in] CmdLine the command line to run. + @param[in] ParamProtocol the shell parameters protocol pointer + + @retval EFI_SUCCESS the script completed successfully +**/ +EFI_STATUS +RunScriptFile ( + IN CONST CHAR16 *ScriptPath, + IN SHELL_FILE_HANDLE Handle OPTIONAL, + IN CONST CHAR16 *CmdLine, + IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol + ) +{ + EFI_STATUS Status; + SHELL_FILE_HANDLE FileHandle; + UINTN Argc; + CHAR16 **Argv; + + if (ShellIsFile(ScriptPath) != EFI_SUCCESS) { + return (EFI_INVALID_PARAMETER); + } + + // + // get the argc and argv updated for scripts + // + Status = UpdateArgcArgv(ParamProtocol, CmdLine, Script_File_Name, &Argv, &Argc); + if (!EFI_ERROR(Status)) { + + if (Handle == NULL) { + // + // open the file + // + Status = ShellOpenFileByName(ScriptPath, &FileHandle, EFI_FILE_MODE_READ, 0); + if (!EFI_ERROR(Status)) { + // + // run it + // + Status = RunScriptFileHandle(FileHandle, ScriptPath); + + // + // now close the file + // + ShellCloseFile(&FileHandle); + } + } else { + Status = RunScriptFileHandle(Handle, ScriptPath); + } + } + + // + // This is guaranteed to be called after UpdateArgcArgv no matter what else happened. + // This is safe even if the update API failed. In this case, it may be a no-op. + // + RestoreArgcArgv(ParamProtocol, &Argv, &Argc); + + return (Status); +} + +/** + Return the pointer to the first occurrence of any character from a list of characters. + + @param[in] String the string to parse + @param[in] CharacterList the list of character to look for + @param[in] EscapeCharacter An escape character to skip + + @return the location of the first character in the string + @retval CHAR_NULL no instance of any character in CharacterList was found in String +**/ +CONST CHAR16* +FindFirstCharacter( + IN CONST CHAR16 *String, + IN CONST CHAR16 *CharacterList, + IN CONST CHAR16 EscapeCharacter + ) +{ + UINT32 WalkChar; + UINT32 WalkStr; + + for (WalkStr = 0; WalkStr < StrLen(String); WalkStr++) { + if (String[WalkStr] == EscapeCharacter) { + WalkStr++; + continue; + } + for (WalkChar = 0; WalkChar < StrLen(CharacterList); WalkChar++) { + if (String[WalkStr] == CharacterList[WalkChar]) { + return (&String[WalkStr]); + } + } + } + return (String + StrLen(String)); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/Shell.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/Shell.h new file mode 100644 index 00000000..2b302dab --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/Shell.h @@ -0,0 +1,390 @@ +/** @file + function definitions for internal to shell functions. + + (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SHELL_INTERNAL_HEADER_ +#define _SHELL_INTERNAL_HEADER_ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ShellParametersProtocol.h" +#include "ShellProtocol.h" +#include "ShellEnvVar.h" +#include "ConsoleLogger.h" +#include "ShellManParser.h" +#include "ConsoleWrappers.h" +#include "FileHandleWrappers.h" + +extern CONST CHAR16 mNoNestingEnvVarName[]; +extern CONST CHAR16 mNoNestingTrue[]; +extern CONST CHAR16 mNoNestingFalse[]; + +typedef struct { + LIST_ENTRY Link; ///< Standard linked list handler. + SHELL_FILE_HANDLE SplitStdOut; ///< ConsoleOut for use in the split. + SHELL_FILE_HANDLE SplitStdIn; ///< ConsoleIn for use in the split. +} SPLIT_LIST; + +typedef struct { + UINT32 Startup:1; ///< Was "-startup" found on command line. + UINT32 NoStartup:1; ///< Was "-nostartup" found on command line. + UINT32 NoConsoleOut:1; ///< Was "-noconsoleout" found on command line. + UINT32 NoConsoleIn:1; ///< Was "-noconsolein" found on command line. + UINT32 NoInterrupt:1; ///< Was "-nointerrupt" found on command line. + UINT32 NoMap:1; ///< Was "-nomap" found on command line. + UINT32 NoVersion:1; ///< Was "-noversion" found on command line. + UINT32 Delay:1; ///< Was "-delay[:n] found on command line + UINT32 Exit:1; ///< Was "-_exit" found on command line + UINT32 NoNest:1; ///< Was "-nonest" found on command line + UINT32 Reserved:7; ///< Extra bits +} SHELL_BITS; + +typedef union { + SHELL_BITS Bits; + UINT16 AllBits; +} SHELL_BIT_UNION; + +typedef struct { + SHELL_BIT_UNION BitUnion; + UINTN Delay; ///< Seconds of delay default:5. + CHAR16 *FileName; ///< Filename to run upon successful initialization. + CHAR16 *FileOptions; ///< Options to pass to FileName. +} SHELL_INIT_SETTINGS; + +typedef struct { + BUFFER_LIST CommandHistory; + UINTN VisibleRowNumber; + UINTN OriginalVisibleRowNumber; + BOOLEAN InsertMode; ///< Is the current typing mode insert (FALSE = overwrite). +} SHELL_VIEWING_SETTINGS; + +typedef struct { + EFI_SHELL_PARAMETERS_PROTOCOL *NewShellParametersProtocol; + EFI_SHELL_PROTOCOL *NewEfiShellProtocol; + BOOLEAN PageBreakEnabled; + BOOLEAN RootShellInstance; + SHELL_INIT_SETTINGS ShellInitSettings; + BUFFER_LIST BufferToFreeList; ///< List of buffers that were returned to the user to free. + SHELL_VIEWING_SETTINGS ViewingSettings; + EFI_HII_HANDLE HiiHandle; ///< Handle from HiiLib. + UINTN LogScreenCount; ///< How many screens of log information to save. + EFI_EVENT UserBreakTimer; ///< Timer event for polling for CTRL-C. + EFI_DEVICE_PATH_PROTOCOL *ImageDevPath; ///< DevicePath for ourselves. + EFI_DEVICE_PATH_PROTOCOL *FileDevPath; ///< DevicePath for ourselves. + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; ///< Pointer for ConsoleInformation. + EFI_SHELL_PARAMETERS_PROTOCOL *OldShellParameters; ///< old shell parameters to reinstall upon exiting. + SHELL_PROTOCOL_HANDLE_LIST OldShellList; ///< List of other instances to reinstall when closing. + SPLIT_LIST SplitList; ///< List of Splits in FILO stack. + VOID *CtrlCNotifyHandle1; ///< The NotifyHandle returned from SimpleTextInputEx.RegisterKeyNotify. + VOID *CtrlCNotifyHandle2; ///< The NotifyHandle returned from SimpleTextInputEx.RegisterKeyNotify. + VOID *CtrlCNotifyHandle3; ///< The NotifyHandle returned from SimpleTextInputEx.RegisterKeyNotify. + VOID *CtrlCNotifyHandle4; ///< The NotifyHandle returned from SimpleTextInputEx.RegisterKeyNotify. + VOID *CtrlSNotifyHandle1; ///< The NotifyHandle returned from SimpleTextInputEx.RegisterKeyNotify. + VOID *CtrlSNotifyHandle2; ///< The NotifyHandle returned from SimpleTextInputEx.RegisterKeyNotify. + VOID *CtrlSNotifyHandle3; ///< The NotifyHandle returned from SimpleTextInputEx.RegisterKeyNotify. + VOID *CtrlSNotifyHandle4; ///< The NotifyHandle returned from SimpleTextInputEx.RegisterKeyNotify. + BOOLEAN HaltOutput; ///< TRUE to start a CTRL-S halt. +} SHELL_INFO; + +#pragma pack(1) +/// +/// HII specific Vendor Device Path definition. +/// +typedef struct { + VENDOR_DEVICE_PATH VendorDevicePath; + EFI_DEVICE_PATH_PROTOCOL End; +} SHELL_MAN_HII_VENDOR_DEVICE_PATH; +#pragma pack() + +extern SHELL_INFO ShellInfoObject; + +/** + Converts the command line to its post-processed form. this replaces variables and alias' per UEFI Shell spec. + + @param[in,out] CmdLine pointer to the command line to update + + @retval EFI_SUCCESS The operation was successful + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @return some other error occurred +**/ +EFI_STATUS +ProcessCommandLineToFinal( + IN OUT CHAR16 **CmdLine + ); + +/** + Function to update the shell variable "lasterror". + + @param[in] ErrorCode the error code to put into lasterror +**/ +EFI_STATUS +SetLastError( + IN CONST SHELL_STATUS ErrorCode + ); + +/** + Sets all the alias' that were registered with the ShellCommandLib library. + + @retval EFI_SUCCESS all init commands were run successfully. +**/ +EFI_STATUS +SetBuiltInAlias( + VOID + ); + +/** + This function will populate the 2 device path protocol parameters based on the + global gImageHandle. the DevPath will point to the device path for the handle that has + loaded image protocol installed on it. the FilePath will point to the device path + for the file that was loaded. + + @param[in, out] DevPath on a successful return the device path to the loaded image + @param[in, out] FilePath on a successful return the device path to the file + + @retval EFI_SUCCESS the 2 device paths were successfully returned. + @return other a error from gBS->HandleProtocol + + @sa HandleProtocol +**/ +EFI_STATUS +GetDevicePathsForImageAndFile ( + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevPath, + IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath + ); + +/** + Process all Uefi Shell 2.0 command line options. + + see Uefi Shell 2.0 section 3.2 for full details. + + the command line should resemble the following: + + shell.efi [ShellOpt-options] [options] [file-name [file-name-options]] + + ShellOpt options Options which control the initialization behavior of the shell. + These options are read from the EFI global variable "ShellOpt" + and are processed before options or file-name. + + options Options which control the initialization behavior of the shell. + + file-name The name of a UEFI shell application or script to be executed + after initialization is complete. By default, if file-name is + specified, then -nostartup is implied. Scripts are not supported + by level 0. + + file-nameoptions The command-line options that are passed to file-name when it + is invoked. + + This will initialize the ShellInitSettings global variable. + + @retval EFI_SUCCESS the variable is initialized. +**/ +EFI_STATUS +ProcessCommandLine( + VOID + ); + +/** + Handles all interaction with the default startup script. + + this will check that the correct command line parameters were passed, handle the delay, and then start running the script. + + @param[in] ImagePath The path to the image for shell. The first place to look for the startup script. + @param[in] FilePath The path to the file for shell. The second place to look for the startup script. + + @retval EFI_SUCCESS The variable is initialized. +**/ +EFI_STATUS +DoStartupScript( + IN EFI_DEVICE_PATH_PROTOCOL *ImagePath, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath + ); + +/** + Function to perform the shell prompt looping. It will do a single prompt, + dispatch the result, and then return. It is expected that the caller will + call this function in a loop many times. + + @retval EFI_SUCCESS + @retval RETURN_ABORTED +**/ +EFI_STATUS +DoShellPrompt ( + VOID + ); + +/** + Add a buffer to the Buffer To Free List for safely returning buffers to other + places without risking letting them modify internal shell information. + + @param Buffer Something to pass to FreePool when the shell is exiting. +**/ +VOID* +AddBufferToFreeList( + VOID *Buffer + ); + +/** + Add a buffer to the Command History List. + + @param Buffer[in] The line buffer to add. +**/ +VOID +AddLineToCommandHistory( + IN CONST CHAR16 *Buffer + ); + +/** + Function will process and run a command line. + + This will determine if the command line represents an internal shell command or dispatch an external application. + + @param[in] CmdLine the command line to parse + + @retval EFI_SUCCESS the command was completed + @retval EFI_ABORTED the command's operation was aborted +**/ +EFI_STATUS +RunCommand( + IN CONST CHAR16 *CmdLine + ); + +/** + Function will process and run a command line. + + This will determine if the command line represents an internal shell + command or dispatch an external application. + + @param[in] CmdLine The command line to parse. + @param[out] CommandStatus The status from the command line. + + @retval EFI_SUCCESS The command was completed. + @retval EFI_ABORTED The command's operation was aborted. +**/ +EFI_STATUS +RunShellCommand( + IN CONST CHAR16 *CmdLine, + OUT EFI_STATUS *CommandStatus + ); + + +/** + Function to process a NSH script file via SHELL_FILE_HANDLE. + + @param[in] Handle The handle to the already opened file. + @param[in] Name The name of the script file. + + @retval EFI_SUCCESS the script completed successfully +**/ +EFI_STATUS +RunScriptFileHandle ( + IN SHELL_FILE_HANDLE Handle, + IN CONST CHAR16 *Name + ); + +/** + Function to process a NSH script file. + + @param[in] ScriptPath Pointer to the script file name (including file system path). + @param[in] Handle the handle of the script file already opened. + @param[in] CmdLine the command line to run. + @param[in] ParamProtocol the shell parameters protocol pointer + + @retval EFI_SUCCESS the script completed successfully +**/ +EFI_STATUS +RunScriptFile ( + IN CONST CHAR16 *ScriptPath, + IN SHELL_FILE_HANDLE Handle OPTIONAL, + IN CONST CHAR16 *CmdLine, + IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol + ); + +/** + Return the pointer to the first occurrence of any character from a list of characters. + + @param[in] String the string to parse + @param[in] CharacterList the list of character to look for + @param[in] EscapeCharacter An escape character to skip + + @return the location of the first character in the string + @retval CHAR_NULL no instance of any character in CharacterList was found in String +**/ +CONST CHAR16* +FindFirstCharacter( + IN CONST CHAR16 *String, + IN CONST CHAR16 *CharacterList, + IN CONST CHAR16 EscapeCharacter + ); + +/** + Cleans off leading and trailing spaces and tabs. + + @param[in] String pointer to the string to trim them off. +**/ +EFI_STATUS +TrimSpaces( + IN CHAR16 **String + ); + +/** + + Create a new buffer list and stores the old one to OldBufferList + + @param OldBufferList The temporary list head used to store the nodes in BufferToFreeList. +**/ +VOID +SaveBufferList ( + OUT LIST_ENTRY *OldBufferList + ); + +/** + Restore previous nodes into BufferToFreeList . + + @param OldBufferList The temporary list head used to store the nodes in BufferToFreeList. +**/ +VOID +RestoreBufferList ( + IN OUT LIST_ENTRY *OldBufferList + ); + + + +#endif //_SHELL_INTERNAL_HEADER_ + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/Shell.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/Shell.inf new file mode 100644 index 00000000..b6564500 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/Shell.inf @@ -0,0 +1,105 @@ +## @file +# This is the shell application +# +# (C) Copyright 2013 Hewlett-Packard Development Company, L.P.
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = Shell + FILE_GUID = 7C04A583-9E3E-4f1c-AD65-E05268D0B4D1 # gUefiShellFileGuid + 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] + Shell.c + Shell.h + ShellParametersProtocol.c + ShellParametersProtocol.h + ShellProtocol.c + ShellProtocol.h + FileHandleWrappers.c + FileHandleWrappers.h + FileHandleInternal.h + ShellEnvVar.c + ShellEnvVar.h + ShellManParser.c + ShellManParser.h + Shell.uni + ConsoleLogger.c + ConsoleLogger.h + ConsoleWrappers.c + ConsoleWrappers.h + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + BaseLib + UefiApplicationEntryPoint + UefiLib + DebugLib + MemoryAllocationLib + ShellCommandLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + DevicePathLib + BaseMemoryLib + PcdLib + FileHandleLib + PrintLib + HiiLib + SortLib + HandleParsingLib + UefiHiiServicesLib + +[Guids] + gShellVariableGuid ## SOMETIMES_CONSUMES ## GUID + gShellAliasGuid ## SOMETIMES_CONSUMES ## GUID + gShellAliasGuid ## SOMETIMES_PRODUCES ## GUID + +[Protocols] + gEfiShellProtocolGuid ## PRODUCES + ## SOMETIMES_CONSUMES + gEfiShellParametersProtocolGuid ## PRODUCES + ## SOMETIMES_CONSUMES + +# gEfiShellEnvironment2Guid ## SOMETIMES_PRODUCES +# gEfiShellInterfaceGuid ## SOMETIMES_PRODUCES + + gEfiSimpleTextInputExProtocolGuid ## CONSUMES + gEfiSimpleTextInProtocolGuid ## CONSUMES + gEfiSimpleTextOutProtocolGuid ## CONSUMES + gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES + gEfiLoadedImageProtocolGuid ## CONSUMES + gEfiComponentName2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiUnicodeCollation2ProtocolGuid ## CONSUMES + gEfiDevicePathProtocolGuid ## CONSUMES + gEfiHiiPackageListProtocolGuid ## SOMETIMES_PRODUCES + +[Pcd] + gEfiShellPkgTokenSpaceGuid.PcdShellSupportLevel ## CONSUMES + gEfiShellPkgTokenSpaceGuid.PcdShellSupportOldProtocols ## CONSUMES + gEfiShellPkgTokenSpaceGuid.PcdShellRequireHiiPlatform ## CONSUMES + gEfiShellPkgTokenSpaceGuid.PcdShellSupportFrameworkHii ## CONSUMES + gEfiShellPkgTokenSpaceGuid.PcdShellPageBreakDefault ## CONSUMES + gEfiShellPkgTokenSpaceGuid.PcdShellInsertModeDefault ## CONSUMES + gEfiShellPkgTokenSpaceGuid.PcdShellScreenLogCount ## CONSUMES + gEfiShellPkgTokenSpaceGuid.PcdShellPrintBufferSize ## CONSUMES + gEfiShellPkgTokenSpaceGuid.PcdShellForceConsole ## CONSUMES + gEfiShellPkgTokenSpaceGuid.PcdShellSupplier ## CONSUMES + gEfiShellPkgTokenSpaceGuid.PcdShellMaxHistoryCommandCount ## CONSUMES diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/Shell.uni b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/Shell.uni new file mode 100644 index 00000000..7dd00726 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/Shell.uni @@ -0,0 +1,52 @@ +// *++ +// +// (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
+// Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// Module Name: +// +// ShellStrings.uni +// +// Abstract: +// +// String definitions for the main UEFI Shell 2.0 application +// +// Revision History: +// +// --*/ + +/=# + +#langdef en-US "English" + +#string STR_SHELL_CURDIR #language en-US "%E%s\> %N" +#string STR_GEN_PROBLEM #language en-US "The argument '%B%s%N' is incorrect.\r\n" +#string STR_SHELL_SHELL #language en-US "%EShell> %N" + +#string STR_SHELL_STARTUP_QUESTION #language en-US "%NPress %HESC%N in %d seconds to skip %Estartup.nsh%N or any other key to continue." + +#string STR_SHELL_ENTER_TO_CONT #language en-US "%NPress ENTER to continue:%E" +#string STR_SHELL_QUIT_CONT #language en-US "%NPress ENTER to continue or 'Q' break:%E" + +#string STR_SHELL_NOT_FOUND #language en-US "%N'%E%s%N' is not recognized as an internal or external command, operable program, or script file.\r\n" + +#string STR_SHELL_CRLF #language en-US "\r\n" + +#string STR_SHELL_ERROR #language en-US "%NCommand Error Status: %r\r\n" +#string STR_SHELL_ERROR_SCRIPT #language en-US "%NScript Error Status: %r (line number %d)\r\n" + +#string STR_SHELL_INVALID_MAPPING #language en-US "%N'%B%s%N' is not a valid mapping.\r\n" +#string STR_SHELL_INVALID_SPLIT #language en-US "Invalid use of pipe (%B|%N).\r\n" + +#string STR_SHELL_INVALID_REDIR #language en-US "Unable to redirect file.\r\n" +#string STR_SHELL_REDUNDA_REDIR #language en-US "Redundant redirection specified.\r\n" + +#string STR_VER_OUTPUT_MAIN_SHELL #language en-US "UEFI %s Shell v%d.%d\r\n" +#string STR_VER_OUTPUT_MAIN_SUPPLIER #language en-US "%s\r\n" +#string STR_VER_OUTPUT_MAIN_UEFI #language en-US "UEFI v%d.%02d (%s, 0x%08x)\r\n" + +#string STR_SHELL_NO_IN_EX #language en-US "No SimpleTextInputEx was found. CTRL-based features are not usable.\r\n" + +#string STR_SHELL_IMAGE_NOT_APP #language en-US "The image is not an application.\r\n" + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellEnvVar.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellEnvVar.c new file mode 100644 index 00000000..a9a0c245 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellEnvVar.c @@ -0,0 +1,572 @@ +/** @file + function declarations for shell environment functions. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Shell.h" + +#define INIT_NAME_BUFFER_SIZE 128 +#define INIT_DATA_BUFFER_SIZE 1024 + +// +// The list is used to cache the environment variables. +// +ENV_VAR_LIST gShellEnvVarList; + +/** + Reports whether an environment variable is Volatile or Non-Volatile. + + @param EnvVarName The name of the environment variable in question + @param Volatile Return TRUE if the environment variable is volatile + + @retval EFI_SUCCESS The volatile attribute is returned successfully + @retval others Some errors happened. +**/ +EFI_STATUS +IsVolatileEnv ( + IN CONST CHAR16 *EnvVarName, + OUT BOOLEAN *Volatile + ) +{ + EFI_STATUS Status; + UINTN Size; + VOID *Buffer; + UINT32 Attribs; + + ASSERT (Volatile != NULL); + + Size = 0; + Buffer = NULL; + + // + // get the variable + // + Status = gRT->GetVariable((CHAR16*)EnvVarName, + &gShellVariableGuid, + &Attribs, + &Size, + Buffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + Buffer = AllocateZeroPool(Size); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Status = gRT->GetVariable((CHAR16*)EnvVarName, + &gShellVariableGuid, + &Attribs, + &Size, + Buffer); + FreePool(Buffer); + } + // + // not found means volatile + // + if (Status == EFI_NOT_FOUND) { + *Volatile = TRUE; + return EFI_SUCCESS; + } + if (EFI_ERROR (Status)) { + return Status; + } + + // + // check for the Non Volatile bit + // + *Volatile = !(BOOLEAN) ((Attribs & EFI_VARIABLE_NON_VOLATILE) == EFI_VARIABLE_NON_VOLATILE); + return EFI_SUCCESS; +} + +/** + free function for ENV_VAR_LIST objects. + + @param[in] List The pointer to pointer to list. +**/ +VOID +FreeEnvironmentVariableList( + IN LIST_ENTRY *List + ) +{ + ENV_VAR_LIST *Node; + + ASSERT (List != NULL); + if (List == NULL) { + return; + } + + for ( Node = (ENV_VAR_LIST*)GetFirstNode(List) + ; !IsListEmpty(List) + ; Node = (ENV_VAR_LIST*)GetFirstNode(List) + ){ + ASSERT(Node != NULL); + RemoveEntryList(&Node->Link); + if (Node->Key != NULL) { + FreePool(Node->Key); + } + if (Node->Val != NULL) { + FreePool(Node->Val); + } + FreePool(Node); + } +} + +/** + Creates a list of all Shell-Guid-based environment variables. + + @param[in, out] ListHead The pointer to pointer to LIST ENTRY object for + storing this list. + + @retval EFI_SUCCESS the list was created successfully. +**/ +EFI_STATUS +GetEnvironmentVariableList( + IN OUT LIST_ENTRY *ListHead + ) +{ + CHAR16 *VariableName; + UINTN NameSize; + UINTN NameBufferSize; + EFI_STATUS Status; + EFI_GUID Guid; + UINTN ValSize; + UINTN ValBufferSize; + ENV_VAR_LIST *VarList; + + if (ListHead == NULL) { + return (EFI_INVALID_PARAMETER); + } + + Status = EFI_SUCCESS; + + ValBufferSize = INIT_DATA_BUFFER_SIZE; + NameBufferSize = INIT_NAME_BUFFER_SIZE; + VariableName = AllocateZeroPool(NameBufferSize); + if (VariableName == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + *VariableName = CHAR_NULL; + + while (!EFI_ERROR(Status)) { + NameSize = NameBufferSize; + Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid); + if (Status == EFI_NOT_FOUND){ + Status = EFI_SUCCESS; + break; + } else if (Status == EFI_BUFFER_TOO_SMALL) { + NameBufferSize = NameSize > NameBufferSize * 2 ? NameSize : NameBufferSize * 2; + SHELL_FREE_NON_NULL(VariableName); + VariableName = AllocateZeroPool(NameBufferSize); + if (VariableName == NULL) { + Status = EFI_OUT_OF_RESOURCES; + break; + } + NameSize = NameBufferSize; + Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid); + } + + if (!EFI_ERROR(Status) && CompareGuid(&Guid, &gShellVariableGuid)){ + VarList = AllocateZeroPool(sizeof(ENV_VAR_LIST)); + if (VarList == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + ValSize = ValBufferSize; + // + // We need another CHAR16 to save '\0' in VarList->Val. + // + VarList->Val = AllocateZeroPool (ValSize + sizeof (CHAR16)); + if (VarList->Val == NULL) { + SHELL_FREE_NON_NULL(VarList); + Status = EFI_OUT_OF_RESOURCES; + break; + } + Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(VariableName, &VarList->Atts, &ValSize, VarList->Val); + if (Status == EFI_BUFFER_TOO_SMALL){ + ValBufferSize = ValSize > ValBufferSize * 2 ? ValSize : ValBufferSize * 2; + SHELL_FREE_NON_NULL (VarList->Val); + // + // We need another CHAR16 to save '\0' in VarList->Val. + // + VarList->Val = AllocateZeroPool (ValBufferSize + sizeof (CHAR16)); + if (VarList->Val == NULL) { + SHELL_FREE_NON_NULL(VarList); + Status = EFI_OUT_OF_RESOURCES; + break; + } + + ValSize = ValBufferSize; + Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(VariableName, &VarList->Atts, &ValSize, VarList->Val); + } + if (!EFI_ERROR(Status)) { + VarList->Key = AllocateCopyPool(StrSize(VariableName), VariableName); + if (VarList->Key == NULL) { + SHELL_FREE_NON_NULL(VarList->Val); + SHELL_FREE_NON_NULL(VarList); + Status = EFI_OUT_OF_RESOURCES; + } else { + InsertTailList(ListHead, &VarList->Link); + } + } else { + SHELL_FREE_NON_NULL(VarList->Val); + SHELL_FREE_NON_NULL(VarList); + } + } // if (VarList == NULL) ... else ... + } // compare guid + } // while + SHELL_FREE_NON_NULL (VariableName); + + if (EFI_ERROR(Status)) { + FreeEnvironmentVariableList(ListHead); + } + + return (Status); +} + +/** + Sets a list of all Shell-Guid-based environment variables. this will + also eliminate all existing shell environment variables (even if they + are not on the list). + + This function will also deallocate the memory from List. + + @param[in] ListHead The pointer to LIST_ENTRY from + GetShellEnvVarList(). + + @retval EFI_SUCCESS the list was Set successfully. +**/ +EFI_STATUS +SetEnvironmentVariableList( + IN LIST_ENTRY *ListHead + ) +{ + ENV_VAR_LIST VarList; + ENV_VAR_LIST *Node; + EFI_STATUS Status; + UINTN Size; + + InitializeListHead(&VarList.Link); + + // + // Delete all the current environment variables + // + Status = GetEnvironmentVariableList(&VarList.Link); + ASSERT_EFI_ERROR(Status); + + for ( Node = (ENV_VAR_LIST*)GetFirstNode(&VarList.Link) + ; !IsNull(&VarList.Link, &Node->Link) + ; Node = (ENV_VAR_LIST*)GetNextNode(&VarList.Link, &Node->Link) + ){ + if (Node->Key != NULL) { + Status = SHELL_DELETE_ENVIRONMENT_VARIABLE(Node->Key); + } + ASSERT_EFI_ERROR(Status); + } + + FreeEnvironmentVariableList(&VarList.Link); + + // + // set all the variables from the list + // + for ( Node = (ENV_VAR_LIST*)GetFirstNode(ListHead) + ; !IsNull(ListHead, &Node->Link) + ; Node = (ENV_VAR_LIST*)GetNextNode(ListHead, &Node->Link) + ){ + Size = StrSize (Node->Val) - sizeof (CHAR16); + if (Node->Atts & EFI_VARIABLE_NON_VOLATILE) { + Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV(Node->Key, Size, Node->Val); + } else { + Status = SHELL_SET_ENVIRONMENT_VARIABLE_V (Node->Key, Size, Node->Val); + } + ASSERT_EFI_ERROR(Status); + } + FreeEnvironmentVariableList(ListHead); + + return (Status); +} + +/** + sets a list of all Shell-Guid-based environment variables. + + @param Environment Points to a NULL-terminated array of environment + variables with the format 'x=y', where x is the + environment variable name and y is the value. + + @retval EFI_SUCCESS The command executed successfully. + @retval EFI_INVALID_PARAMETER The parameter is invalid. + @retval EFI_OUT_OF_RESOURCES Out of resources. + + @sa SetEnvironmentVariableList +**/ +EFI_STATUS +SetEnvironmentVariables( + IN CONST CHAR16 **Environment + ) +{ + CONST CHAR16 *CurrentString; + UINTN CurrentCount; + ENV_VAR_LIST *VarList; + ENV_VAR_LIST *Node; + + VarList = NULL; + + if (Environment == NULL) { + return (EFI_INVALID_PARAMETER); + } + + // + // Build a list identical to the ones used for get/set list functions above + // + for ( CurrentCount = 0 + ; + ; CurrentCount++ + ){ + CurrentString = Environment[CurrentCount]; + if (CurrentString == NULL) { + break; + } + ASSERT(StrStr(CurrentString, L"=") != NULL); + Node = AllocateZeroPool(sizeof(ENV_VAR_LIST)); + if (Node == NULL) { + SetEnvironmentVariableList(&VarList->Link); + return (EFI_OUT_OF_RESOURCES); + } + + Node->Key = AllocateZeroPool((StrStr(CurrentString, L"=") - CurrentString + 1) * sizeof(CHAR16)); + if (Node->Key == NULL) { + SHELL_FREE_NON_NULL(Node); + SetEnvironmentVariableList(&VarList->Link); + return (EFI_OUT_OF_RESOURCES); + } + + // + // Copy the string into the Key, leaving the last character allocated as NULL to terminate + // + StrnCpyS( Node->Key, + StrStr(CurrentString, L"=") - CurrentString + 1, + CurrentString, + StrStr(CurrentString, L"=") - CurrentString + ); + + // + // ValueSize = TotalSize - already removed size - size for '=' + size for terminator (the last 2 items cancel each other) + // + Node->Val = AllocateCopyPool(StrSize(CurrentString) - StrSize(Node->Key), CurrentString + StrLen(Node->Key) + 1); + if (Node->Val == NULL) { + SHELL_FREE_NON_NULL(Node->Key); + SHELL_FREE_NON_NULL(Node); + SetEnvironmentVariableList(&VarList->Link); + return (EFI_OUT_OF_RESOURCES); + } + + Node->Atts = EFI_VARIABLE_BOOTSERVICE_ACCESS; + + if (VarList == NULL) { + VarList = AllocateZeroPool(sizeof(ENV_VAR_LIST)); + if (VarList == NULL) { + SHELL_FREE_NON_NULL(Node->Key); + SHELL_FREE_NON_NULL(Node->Val); + SHELL_FREE_NON_NULL(Node); + return (EFI_OUT_OF_RESOURCES); + } + InitializeListHead(&VarList->Link); + } + InsertTailList(&VarList->Link, &Node->Link); + + } // for loop + + // + // set this new list as the set of all environment variables. + // this function also frees the memory and deletes all pre-existing + // shell-guid based environment variables. + // + return (SetEnvironmentVariableList(&VarList->Link)); +} + +/** + Find an environment variable in the gShellEnvVarList. + + @param Key The name of the environment variable. + @param Value The value of the environment variable, the buffer + shoule be freed by the caller. + @param ValueSize The size in bytes of the environment variable + including the tailing CHAR_NELL. + @param Atts The attributes of the variable. + + @retval EFI_SUCCESS The command executed successfully. + @retval EFI_NOT_FOUND The environment variable is not found in + gShellEnvVarList. + +**/ +EFI_STATUS +ShellFindEnvVarInList ( + IN CONST CHAR16 *Key, + OUT CHAR16 **Value, + OUT UINTN *ValueSize, + OUT UINT32 *Atts OPTIONAL + ) +{ + ENV_VAR_LIST *Node; + + if (Key == NULL || Value == NULL || ValueSize == NULL) { + return SHELL_INVALID_PARAMETER; + } + + for ( Node = (ENV_VAR_LIST*)GetFirstNode(&gShellEnvVarList.Link) + ; !IsNull(&gShellEnvVarList.Link, &Node->Link) + ; Node = (ENV_VAR_LIST*)GetNextNode(&gShellEnvVarList.Link, &Node->Link) + ){ + if (Node->Key != NULL && StrCmp(Key, Node->Key) == 0) { + *Value = AllocateCopyPool(StrSize(Node->Val), Node->Val); + *ValueSize = StrSize(Node->Val); + if (Atts != NULL) { + *Atts = Node->Atts; + } + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** + Add an environment variable into gShellEnvVarList. + + @param Key The name of the environment variable. + @param Value The value of environment variable. + @param ValueSize The size in bytes of the environment variable + including the tailing CHAR_NULL + @param Atts The attributes of the variable. + + @retval EFI_SUCCESS The environment variable was added to list successfully. + @retval others Some errors happened. + +**/ +EFI_STATUS +ShellAddEnvVarToList ( + IN CONST CHAR16 *Key, + IN CONST CHAR16 *Value, + IN UINTN ValueSize, + IN UINT32 Atts + ) +{ + ENV_VAR_LIST *Node; + CHAR16 *LocalKey; + CHAR16 *LocalValue; + + if (Key == NULL || Value == NULL || ValueSize == 0) { + return EFI_INVALID_PARAMETER; + } + + LocalValue = AllocateCopyPool (ValueSize, Value); + if (LocalValue == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Update the variable value if it exists in gShellEnvVarList. + // + for ( Node = (ENV_VAR_LIST*)GetFirstNode(&gShellEnvVarList.Link) + ; !IsNull(&gShellEnvVarList.Link, &Node->Link) + ; Node = (ENV_VAR_LIST*)GetNextNode(&gShellEnvVarList.Link, &Node->Link) + ){ + if (Node->Key != NULL && StrCmp(Key, Node->Key) == 0) { + Node->Atts = Atts; + SHELL_FREE_NON_NULL(Node->Val); + Node->Val = LocalValue; + return EFI_SUCCESS; + } + } + + // + // If the environment variable key doesn't exist in list just insert + // a new node. + // + LocalKey = AllocateCopyPool (StrSize(Key), Key); + if (LocalKey == NULL) { + FreePool (LocalValue); + return EFI_OUT_OF_RESOURCES; + } + Node = (ENV_VAR_LIST*)AllocateZeroPool (sizeof(ENV_VAR_LIST)); + if (Node == NULL) { + FreePool (LocalKey); + FreePool (LocalValue); + return EFI_OUT_OF_RESOURCES; + } + Node->Key = LocalKey; + Node->Val = LocalValue; + Node->Atts = Atts; + InsertTailList(&gShellEnvVarList.Link, &Node->Link); + + return EFI_SUCCESS; +} + +/** + Remove a specified environment variable in gShellEnvVarList. + + @param Key The name of the environment variable. + + @retval EFI_SUCCESS The command executed successfully. + @retval EFI_NOT_FOUND The environment variable is not found in + gShellEnvVarList. +**/ +EFI_STATUS +ShellRemvoeEnvVarFromList ( + IN CONST CHAR16 *Key + ) +{ + ENV_VAR_LIST *Node; + + if (Key == NULL) { + return EFI_INVALID_PARAMETER; + } + + for ( Node = (ENV_VAR_LIST*)GetFirstNode(&gShellEnvVarList.Link) + ; !IsNull(&gShellEnvVarList.Link, &Node->Link) + ; Node = (ENV_VAR_LIST*)GetNextNode(&gShellEnvVarList.Link, &Node->Link) + ){ + if (Node->Key != NULL && StrCmp(Key, Node->Key) == 0) { + SHELL_FREE_NON_NULL(Node->Key); + SHELL_FREE_NON_NULL(Node->Val); + RemoveEntryList(&Node->Link); + SHELL_FREE_NON_NULL(Node); + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** + Initialize the gShellEnvVarList and cache all Shell-Guid-based environment + variables. + +**/ +EFI_STATUS +ShellInitEnvVarList ( + VOID + ) +{ + EFI_STATUS Status; + + InitializeListHead(&gShellEnvVarList.Link); + Status = GetEnvironmentVariableList (&gShellEnvVarList.Link); + + return Status; +} + +/** + Destructe the gShellEnvVarList. + +**/ +VOID +ShellFreeEnvVarList ( + VOID + ) +{ + FreeEnvironmentVariableList (&gShellEnvVarList.Link); + InitializeListHead(&gShellEnvVarList.Link); + + return; +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellEnvVar.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellEnvVar.h new file mode 100644 index 00000000..b97966ab --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellEnvVar.h @@ -0,0 +1,282 @@ +/** @file + function definitions for shell environment functions. + + the following includes are required: +//#include +//#include + + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SHELL_ENVIRONMENT_VARIABLE_HEADER_ +#define _SHELL_ENVIRONMENT_VARIABLE_HEADER_ + +typedef struct { + LIST_ENTRY Link; + CHAR16 *Key; + CHAR16 *Val; + UINT32 Atts; +} ENV_VAR_LIST; + +// +// The list is used to cache the environment variables. +// +extern ENV_VAR_LIST gShellEnvVarList; + + +/** + Reports whether an environment variable is Volatile or Non-Volatile. + + @param EnvVarName The name of the environment variable in question + @param Volatile Return TRUE if the environment variable is volatile + + @retval EFI_SUCCESS The volatile attribute is returned successfully + @retval others Some errors happened. +**/ +EFI_STATUS +IsVolatileEnv ( + IN CONST CHAR16 *EnvVarName, + OUT BOOLEAN *Volatile + ); + +/** + Delete a Non-Volatile environment variable. + + This will use the Runtime Services call SetVariable to remove a non-volatile variable. + + @param EnvVarName The name of the environment variable in question + + @retval EFI_SUCCESS The variable was deleted successfully + @retval other An error occurred + @sa SetVariable +**/ +#define SHELL_DELETE_ENVIRONMENT_VARIABLE(EnvVarName) \ + (gRT->SetVariable((CHAR16*)EnvVarName, \ + &gShellVariableGuid, \ + 0, \ + 0, \ + NULL)) + +/** + Set a Non-Volatile environment variable. + + This will use the Runtime Services call SetVariable to set a non-volatile variable. + + @param EnvVarName The name of the environment variable in question + @param BufferSize UINTN size of Buffer + @param Buffer Pointer to value to set variable to + + @retval EFI_SUCCESS The variable was changed successfully + @retval other An error occurred + @sa SetVariable +**/ +#define SHELL_SET_ENVIRONMENT_VARIABLE_NV(EnvVarName,BufferSize,Buffer) \ + (gRT->SetVariable((CHAR16*)EnvVarName, \ + &gShellVariableGuid, \ + EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS, \ + BufferSize, \ + (VOID*)Buffer)) + +/** + Get an environment variable. + + This will use the Runtime Services call GetVariable to get a variable. + + @param EnvVarName The name of the environment variable in question + @param BufferSize Pointer to the UINTN size of Buffer + @param Buffer Pointer buffer to get variable value into + + @retval EFI_SUCCESS The variable's value was retrieved successfully + @retval other An error occurred + @sa SetVariable +**/ +#define SHELL_GET_ENVIRONMENT_VARIABLE(EnvVarName,BufferSize,Buffer) \ + (gRT->GetVariable((CHAR16*)EnvVarName, \ + &gShellVariableGuid, \ + 0, \ + BufferSize, \ + Buffer)) + +/** + Get an environment variable. + + This will use the Runtime Services call GetVariable to get a variable. + + @param EnvVarName The name of the environment variable in question + @param Atts Pointer to the UINT32 for attributes (or NULL) + @param BufferSize Pointer to the UINTN size of Buffer + @param Buffer Pointer buffer to get variable value into + + @retval EFI_SUCCESS The variable's value was retrieved successfully + @retval other An error occurred + @sa SetVariable +**/ +#define SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(EnvVarName,Atts,BufferSize,Buffer) \ + (gRT->GetVariable((CHAR16*)EnvVarName, \ + &gShellVariableGuid, \ + Atts, \ + BufferSize, \ + Buffer)) + +/** + Set a Volatile environment variable. + + This will use the Runtime Services call SetVariable to set a volatile variable. + + @param EnvVarName The name of the environment variable in question + @param BufferSize UINTN size of Buffer + @param Buffer Pointer to value to set variable to + + @retval EFI_SUCCESS The variable was changed successfully + @retval other An error occurred + @sa SetVariable +**/ +#define SHELL_SET_ENVIRONMENT_VARIABLE_V(EnvVarName,BufferSize,Buffer) \ + (gRT->SetVariable((CHAR16*)EnvVarName, \ + &gShellVariableGuid, \ + EFI_VARIABLE_BOOTSERVICE_ACCESS, \ + BufferSize, \ + (VOID*)Buffer)) + +/** + Creates a list of all Shell-Guid-based environment variables. + + @param[in, out] List The pointer to pointer to LIST_ENTRY object for + storing this list. + + @retval EFI_SUCCESS the list was created successfully. +**/ +EFI_STATUS +GetEnvironmentVariableList( + IN OUT LIST_ENTRY *List + ); + +/** + Sets a list of all Shell-Guid-based environment variables. this will + also eliminate all pre-existing shell environment variables (even if they + are not on the list). + + This function will also deallocate the memory from List. + + @param[in] List The pointer to LIST_ENTRY from + GetShellEnvVarList(). + + @retval EFI_SUCCESS The list was Set successfully. +**/ +EFI_STATUS +SetEnvironmentVariableList( + IN LIST_ENTRY *List + ); + +/** + sets all Shell-Guid-based environment variables. this will + also eliminate all pre-existing shell environment variables (even if they + are not on the list). + + @param[in] Environment Points to a NULL-terminated array of environment + variables with the format 'x=y', where x is the + environment variable name and y is the value. + + @retval EFI_SUCCESS The command executed successfully. + @retval EFI_INVALID_PARAMETER The parameter is invalid. + @retval EFI_OUT_OF_RESOURCES Out of resources. + + @sa SetEnvironmentVariableList +**/ +EFI_STATUS +SetEnvironmentVariables( + IN CONST CHAR16 **Environment + ); + +/** + free function for ENV_VAR_LIST objects. + + @param[in] List The pointer to pointer to list. +**/ +VOID +FreeEnvironmentVariableList( + IN LIST_ENTRY *List + ); + +/** + Find an environment variable in the gShellEnvVarList. + + @param Key The name of the environment variable. + @param Value The value of the environment variable, the buffer + shoule be freed by the caller. + @param ValueSize The size in bytes of the environment variable + including the tailing CHAR_NULL. + @param Atts The attributes of the variable. + + @retval EFI_SUCCESS The command executed successfully. + @retval EFI_NOT_FOUND The environment variable is not found in + gShellEnvVarList. + +**/ +EFI_STATUS +ShellFindEnvVarInList ( + IN CONST CHAR16 *Key, + OUT CHAR16 **Value, + OUT UINTN *ValueSize, + OUT UINT32 *Atts OPTIONAL + ); + +/** + Add an environment variable into gShellEnvVarList. + + @param Key The name of the environment variable. + @param Value The value of environment variable. + @param ValueSize The size in bytes of the environment variable + including the tailing CHAR_NULL + @param Atts The attributes of the variable. + + @retval EFI_SUCCESS The environment variable was added to list successfully. + @retval others Some errors happened. + +**/ +EFI_STATUS +ShellAddEnvVarToList ( + IN CONST CHAR16 *Key, + IN CONST CHAR16 *Value, + IN UINTN ValueSize, + IN UINT32 Atts + ); + +/** + Remove a specified environment variable in gShellEnvVarList. + + @param Key The name of the environment variable. + + @retval EFI_SUCCESS The command executed successfully. + @retval EFI_NOT_FOUND The environment variable is not found in + gShellEnvVarList. +**/ +EFI_STATUS +ShellRemvoeEnvVarFromList ( + IN CONST CHAR16 *Key + ); + +/** + Initialize the gShellEnvVarList and cache all Shell-Guid-based environment + variables. + +**/ +EFI_STATUS +ShellInitEnvVarList ( + VOID + ); + +/** + Destructe the gShellEnvVarList. + +**/ +VOID +ShellFreeEnvVarList ( + VOID + ); + +#endif //_SHELL_ENVIRONMENT_VARIABLE_HEADER_ + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellManParser.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellManParser.c new file mode 100644 index 00000000..9bc20e18 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellManParser.c @@ -0,0 +1,757 @@ +/** @file + Provides interface to shell MAN file parser. + + Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.
+ Copyright 2015 Dell Inc. + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Shell.h" + +#define SHELL_MAN_HII_GUID \ +{ \ + 0xf62ccd0c, 0x2449, 0x453c, { 0x8a, 0xcb, 0x8c, 0xc5, 0x7c, 0xf0, 0x2a, 0x97 } \ +} + +EFI_HII_HANDLE mShellManHiiHandle = NULL; +EFI_HANDLE mShellManDriverHandle = NULL; + + +SHELL_MAN_HII_VENDOR_DEVICE_PATH mShellManHiiDevicePath = { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) + } + }, + SHELL_MAN_HII_GUID + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + (UINT8) (END_DEVICE_PATH_LENGTH), + (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) + } + } +}; + +/** + Verifies that the filename has .EFI on the end. + + allocates a new buffer and copies the name (appending .EFI if necessary). + Caller to free the buffer. + + @param[in] NameString original name string + + @return the new filename with .efi as the extension. +**/ +CHAR16 * +GetExecuatableFileName ( + IN CONST CHAR16 *NameString + ) +{ + CHAR16 *Buffer; + CHAR16 *SuffixStr; + if (NameString == NULL) { + return (NULL); + } + + // + // Fix the file name + // + if (StrnCmp(NameString+StrLen(NameString)-StrLen(L".efi"), L".efi", StrLen(L".efi"))==0) { + Buffer = AllocateCopyPool(StrSize(NameString), NameString); + } else if (StrnCmp(NameString+StrLen(NameString)-StrLen(L".man"), L".man", StrLen(L".man"))==0) { + Buffer = AllocateCopyPool(StrSize(NameString), NameString); + if (Buffer != NULL) { + SuffixStr = Buffer+StrLen(Buffer)-StrLen(L".man"); + StrnCpyS (SuffixStr, StrSize(L".man")/sizeof(CHAR16), L".efi", StrLen(L".efi")); + } + } else { + Buffer = AllocateZeroPool(StrSize(NameString) + StrLen(L".efi")*sizeof(CHAR16)); + if (Buffer != NULL) { + StrnCpyS( Buffer, + (StrSize(NameString) + StrLen(L".efi")*sizeof(CHAR16))/sizeof(CHAR16), + NameString, + StrLen(NameString) + ); + StrnCatS( Buffer, + (StrSize(NameString) + StrLen(L".efi")*sizeof(CHAR16))/sizeof(CHAR16), + L".efi", + StrLen(L".efi") + ); + } + } + return (Buffer); + +} + +/** + Verifies that the filename has .MAN on the end. + + allocates a new buffer and copies the name (appending .MAN if necessary) + + ASSERT if ManFileName is NULL + + @param[in] ManFileName original filename + + @return the new filename with .man as the extension. +**/ +CHAR16 * +GetManFileName( + IN CONST CHAR16 *ManFileName + ) +{ + CHAR16 *Buffer; + if (ManFileName == NULL) { + return (NULL); + } + // + // Fix the file name + // + if (StrnCmp(ManFileName+StrLen(ManFileName)-4, L".man", 4)==0) { + Buffer = AllocateCopyPool(StrSize(ManFileName), ManFileName); + } else { + Buffer = AllocateZeroPool(StrSize(ManFileName) + 4*sizeof(CHAR16)); + if (Buffer != NULL) { + StrnCpyS( Buffer, + (StrSize(ManFileName) + 4*sizeof(CHAR16))/sizeof(CHAR16), + ManFileName, + StrLen(ManFileName) + ); + StrnCatS( Buffer, + (StrSize(ManFileName) + 4*sizeof(CHAR16))/sizeof(CHAR16), + L".man", + 4 + ); + } + } + return (Buffer); +} + +/** + Search the path environment variable for possible locations and test for + which one contains a man file with the name specified. If a valid file is found + stop searching and return the (opened) SHELL_FILE_HANDLE for that file. + + @param[in] FileName Name of the file to find and open. + @param[out] Handle Pointer to the handle of the found file. The + value of this is undefined for return values + except EFI_SUCCESS. + + @retval EFI_SUCCESS The file was found. Handle is a valid SHELL_FILE_HANDLE + @retval EFI_INVALID_PARAMETER A parameter had an invalid value. + @retval EFI_NOT_FOUND The file was not found. +**/ +EFI_STATUS +SearchPathForFile( + IN CONST CHAR16 *FileName, + OUT SHELL_FILE_HANDLE *Handle + ) +{ + CHAR16 *FullFileName; + EFI_STATUS Status; + + if ( FileName == NULL + || Handle == NULL + || StrLen(FileName) == 0 + ){ + return (EFI_INVALID_PARAMETER); + } + + FullFileName = ShellFindFilePath(FileName); + if (FullFileName == NULL) { + return (EFI_NOT_FOUND); + } + + // + // now open that file + // + Status = EfiShellOpenFileByName(FullFileName, Handle, EFI_FILE_MODE_READ); + FreePool(FullFileName); + + return (Status); +} + +/** + Parses through the MAN file specified by SHELL_FILE_HANDLE and returns the + detailed help for any sub section specified in the comma separated list of + sections provided. If the end of the file or a .TH section is found then + return. + + Upon a successful return the caller is responsible to free the memory in *HelpText + + @param[in] Handle FileHandle to read from + @param[in] Sections name of command's sub sections to find + @param[out] HelpText pointer to pointer to string where text goes. + @param[out] HelpSize pointer to size of allocated HelpText (may be updated) + @param[in] Ascii TRUE if the file is ASCII, FALSE otherwise. + + @retval EFI_OUT_OF_RESOURCES a memory allocation failed. + @retval EFI_SUCCESS the section was found and its description stored in + an allocated buffer. +**/ +EFI_STATUS +ManFileFindSections( + IN SHELL_FILE_HANDLE Handle, + IN CONST CHAR16 *Sections, + OUT CHAR16 **HelpText, + OUT UINTN *HelpSize, + IN BOOLEAN Ascii + ) +{ + EFI_STATUS Status; + CHAR16 *ReadLine; + UINTN Size; + BOOLEAN CurrentlyReading; + CHAR16 *SectionName; + UINTN SectionLen; + BOOLEAN Found; + + if ( Handle == NULL + || HelpText == NULL + || HelpSize == NULL + ){ + return (EFI_INVALID_PARAMETER); + } + + Status = EFI_SUCCESS; + CurrentlyReading = FALSE; + Size = 1024; + Found = FALSE; + + ReadLine = AllocateZeroPool(Size); + if (ReadLine == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + for (;!ShellFileHandleEof(Handle);Size = 1024) { + Status = ShellFileHandleReadLine(Handle, ReadLine, &Size, TRUE, &Ascii); + if (ReadLine[0] == L'#') { + // + // Skip comment lines + // + continue; + } + // + // ignore too small of buffer... + // + if (Status == EFI_BUFFER_TOO_SMALL) { + Status = EFI_SUCCESS; + } + if (EFI_ERROR(Status)) { + break; + } else if (StrnCmp(ReadLine, L".TH", 3) == 0) { + // + // we hit the end of this commands section so stop. + // + break; + } else if (StrnCmp(ReadLine, L".SH", 3) == 0) { + if (Sections == NULL) { + CurrentlyReading = TRUE; + continue; + } + // + // we found a section + // + if (CurrentlyReading) { + CurrentlyReading = FALSE; + } + // + // is this a section we want to read in? + // + for ( SectionName = ReadLine + 3 + ; *SectionName == L' ' + ; SectionName++); + SectionLen = StrLen(SectionName); + SectionName = StrStr(Sections, SectionName); + if (SectionName == NULL) { + continue; + } + if (*(SectionName + SectionLen) == CHAR_NULL || *(SectionName + SectionLen) == L',') { + CurrentlyReading = TRUE; + } + } else if (CurrentlyReading) { + Found = TRUE; + // + // copy and save the current line. + // + ASSERT((*HelpText == NULL && *HelpSize == 0) || (*HelpText != NULL)); + StrnCatGrow (HelpText, HelpSize, ReadLine, 0); + StrnCatGrow (HelpText, HelpSize, L"\r\n", 0); + } + } + FreePool(ReadLine); + if (!Found && !EFI_ERROR(Status)) { + return (EFI_NOT_FOUND); + } + return (Status); +} + +/** + Parses a line from a MAN file to see if it is the Title Header. If it is, then + if the "Brief Description" is desired, allocate a buffer for it and return a + copy. Upon a successful return the caller is responsible to free the memory in + *BriefDesc + + Uses a simple state machine that allows "unlimited" whitespace before and after the + ".TH", compares Command and the MAN file command name without respect to case, and + allows "unlimited" whitespace and '0' and '1' characters before the Short Description. + The PCRE regex describing this functionality is: ^\s*\.TH\s+(\S)\s[\s01]*(.*)$ + where group 1 is the Command Name and group 2 is the Short Description. + + @param[in] Command name of command whose MAN file we think Line came from + @param[in] Line Pointer to a line from the MAN file + @param[out] BriefDesc pointer to pointer to string where description goes. + @param[out] BriefSize pointer to size of allocated BriefDesc + @param[out] Found TRUE if the Title Header was found and it belongs to Command + + @retval TRUE Line contained the Title Header + @retval FALSE Line did not contain the Title Header +**/ +BOOLEAN +IsTitleHeader( + IN CONST CHAR16 *Command, + IN CHAR16 *Line, + OUT CHAR16 **BriefDesc OPTIONAL, + OUT UINTN *BriefSize OPTIONAL, + OUT BOOLEAN *Found + ) +{ + // The states of a simple state machine used to recognize a title header line + // and to extract the Short Description, if desired. + typedef enum { + LookForThMacro, LookForCommandName, CompareCommands, GetBriefDescription, Final + } STATEVALUES; + + STATEVALUES State; + UINTN CommandIndex; // Indexes Command as we compare its chars to the MAN file. + BOOLEAN ReturnValue; // TRUE if this the Title Header line of *some* MAN file. + BOOLEAN ReturnFound; // TRUE if this the Title Header line of *the desired* MAN file. + + ReturnValue = FALSE; + ReturnFound = FALSE; + CommandIndex = 0; + State = LookForThMacro; + + do { + + if (*Line == L'\0') { + break; + } + + switch (State) { + + // Handle "^\s*.TH\s" + // Go to state LookForCommandName if the title header macro is present; otherwise, + // eat white space. If we see something other than white space, this is not a + // title header line. + case LookForThMacro: + if (StrnCmp (L".TH ", Line, 4) == 0 || StrnCmp (L".TH\t", Line, 4) == 0) { + Line += 4; + State = LookForCommandName; + } + else if (*Line == L' ' || *Line == L'\t') { + Line++; + } + else { + State = Final; + } + break; + + // Handle "\s*" + // Eat any "extra" whitespace after the title header macro (we have already seen + // at least one white space character). Go to state CompareCommands when a + // non-white space is seen. + case LookForCommandName: + if (*Line == L' ' || *Line == L'\t') { + Line++; + } + else { + ReturnValue = TRUE; // This is *some* command's title header line. + State = CompareCommands; + // Do not increment Line; it points to the first character of the command + // name on the title header line. + } + break; + + // Handle "(\S)\s" + // Compare Command to the title header command name, ignoring case. When we + // reach the end of the command (i.e. we see white space), the next state + // depends on whether the caller wants a copy of the Brief Description. + case CompareCommands: + if (*Line == L' ' || *Line == L'\t') { + ReturnFound = TRUE; // This is the desired command's title header line. + State = (BriefDesc == NULL) ? Final : GetBriefDescription; + } + else if (CharToUpper (*Line) != CharToUpper (*(Command + CommandIndex++))) { + State = Final; + } + Line++; + break; + + // Handle "[\s01]*(.*)$" + // Skip whitespace, '0', and '1' characters, if any, prior to the brief description. + // Return the description to the caller. + case GetBriefDescription: + if (*Line != L' ' && *Line != L'\t' && *Line != L'0' && *Line != L'1') { + *BriefSize = StrSize(Line); + *BriefDesc = AllocateZeroPool(*BriefSize); + if (*BriefDesc != NULL) { + StrCpyS(*BriefDesc, (*BriefSize)/sizeof(CHAR16), Line); + } + State = Final; + } + Line++; + break; + + default: + break; + } + + } while (State < Final); + + *Found = ReturnFound; + return ReturnValue; +} + +/** + Parses through the MAN file specified by SHELL_FILE_HANDLE and returns the + "Brief Description" for the .TH section as specified by Command. If the + command section is not found return EFI_NOT_FOUND. + + Upon a successful return the caller is responsible to free the memory in *BriefDesc + + @param[in] Handle FileHandle to read from + @param[in] Command name of command's section to find as entered on the + command line (may be a relative or absolute path or + be in any case: upper, lower, or mixed in numerous ways!). + @param[out] BriefDesc pointer to pointer to string where description goes. + @param[out] BriefSize pointer to size of allocated BriefDesc + @param[in, out] Ascii TRUE if the file is ASCII, FALSE otherwise, will be + set if the file handle is at the 0 position. + + @retval EFI_OUT_OF_RESOURCES a memory allocation failed. + @retval EFI_SUCCESS the section was found and its description stored in + an allocated buffer if requested. +**/ +EFI_STATUS +ManFileFindTitleSection( + IN SHELL_FILE_HANDLE Handle, + IN CONST CHAR16 *Command, + OUT CHAR16 **BriefDesc OPTIONAL, + OUT UINTN *BriefSize OPTIONAL, + IN OUT BOOLEAN *Ascii + ) +{ + EFI_STATUS Status; + CHAR16 *ReadLine; + UINTN Size; + BOOLEAN Found; + UINTN Start; + + if ( Handle == NULL + || Command == NULL + || (BriefDesc != NULL && BriefSize == NULL) + ){ + return (EFI_INVALID_PARAMETER); + } + + Status = EFI_SUCCESS; + Size = 1024; + Found = FALSE; + + ReadLine = AllocateZeroPool(Size); + if (ReadLine == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + // + // Do not pass any leading path information that may be present to IsTitleHeader(). + // + Start = StrLen(Command); + while ((Start != 0) + && (*(Command + Start - 1) != L'\\') + && (*(Command + Start - 1) != L'/') + && (*(Command + Start - 1) != L':')) { + --Start; + } + + for (;!ShellFileHandleEof(Handle);Size = 1024) { + Status = ShellFileHandleReadLine(Handle, ReadLine, &Size, TRUE, Ascii); + // + // ignore too small of buffer... + // + if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) { + break; + } + + Status = EFI_NOT_FOUND; + if (IsTitleHeader (Command+Start, ReadLine, BriefDesc, BriefSize, &Found)) { + Status = Found ? EFI_SUCCESS : EFI_NOT_FOUND; + break; + } + } + + FreePool(ReadLine); + return (Status); +} + +/** + This function returns the help information for the specified command. The help text + will be parsed from a UEFI Shell manual page. (see UEFI Shell 2.0 Appendix B) + + If Sections is specified, then each section name listed will be compared in a casesensitive + manner, to the section names described in Appendix B. If the section exists, + it will be appended to the returned help text. If the section does not exist, no + information will be returned. If Sections is NULL, then all help text information + available will be returned. + + if BriefDesc is NULL, then the breif description will not be saved separately, + but placed first in the main HelpText. + + @param[in] ManFileName Points to the NULL-terminated UEFI Shell MAN file name. + @param[in] Command Points to the NULL-terminated UEFI Shell command name. + @param[in] Sections Points to the NULL-terminated comma-delimited + section names to return. If NULL, then all + sections will be returned. + @param[out] BriefDesc On return, points to a callee-allocated buffer + containing brief description text. + @param[out] HelpText On return, points to a callee-allocated buffer + containing all specified help text. + + @retval EFI_SUCCESS The help text was returned. + @retval EFI_OUT_OF_RESOURCES The necessary buffer could not be allocated to hold the + returned help text. + @retval EFI_INVALID_PARAMETER HelpText is NULL. + @retval EFI_INVALID_PARAMETER ManFileName is invalid. + @retval EFI_NOT_FOUND There is no help text available for Command. +**/ +EFI_STATUS +ProcessManFile( + IN CONST CHAR16 *ManFileName, + IN CONST CHAR16 *Command, + IN CONST CHAR16 *Sections OPTIONAL, + OUT CHAR16 **BriefDesc OPTIONAL, + OUT CHAR16 **HelpText + ) +{ + CHAR16 *TempString; + SHELL_FILE_HANDLE FileHandle; + EFI_HANDLE CmdFileImgHandle; + EFI_STATUS Status; + UINTN HelpSize; + UINTN BriefSize; + UINTN StringIdWalker; + BOOLEAN Ascii; + CHAR16 *CmdFileName; + CHAR16 *CmdFilePathName; + EFI_DEVICE_PATH_PROTOCOL *FileDevPath; + EFI_DEVICE_PATH_PROTOCOL *DevPath; + EFI_HII_PACKAGE_LIST_HEADER *PackageListHeader; + + if ( ManFileName == NULL + || Command == NULL + || HelpText == NULL + ){ + return (EFI_INVALID_PARAMETER); + } + + HelpSize = 0; + BriefSize = 0; + StringIdWalker = 0; + TempString = NULL; + Ascii = FALSE; + CmdFileName = NULL; + CmdFilePathName = NULL; + CmdFileImgHandle = NULL; + PackageListHeader = NULL; + FileDevPath = NULL; + DevPath = NULL; + + // + // See if it's in HII first + // + TempString = ShellCommandGetCommandHelp(Command); + if (TempString != NULL) { + FileHandle = ConvertEfiFileProtocolToShellHandle (CreateFileInterfaceMem (TRUE), NULL); + HelpSize = StrLen (TempString) * sizeof (CHAR16); + ShellWriteFile (FileHandle, &HelpSize, TempString); + ShellSetFilePosition (FileHandle, 0); + HelpSize = 0; + BriefSize = 0; + Status = ManFileFindTitleSection(FileHandle, Command, BriefDesc, &BriefSize, &Ascii); + if (!EFI_ERROR(Status) && HelpText != NULL){ + Status = ManFileFindSections(FileHandle, Sections, HelpText, &HelpSize, Ascii); + } + ShellCloseFile (&FileHandle); + } else { + // + // If the image is a external app, check .MAN file first. + // + FileHandle = NULL; + TempString = GetManFileName(ManFileName); + if (TempString == NULL) { + return (EFI_INVALID_PARAMETER); + } + + Status = SearchPathForFile(TempString, &FileHandle); + if (EFI_ERROR(Status)) { + FileDevPath = FileDevicePath(NULL, TempString); + DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, FileDevPath); + Status = InternalOpenFileDevicePath(DevPath, &FileHandle, EFI_FILE_MODE_READ, 0); + SHELL_FREE_NON_NULL(FileDevPath); + SHELL_FREE_NON_NULL(DevPath); + } + + if (!EFI_ERROR(Status)) { + HelpSize = 0; + BriefSize = 0; + Status = ManFileFindTitleSection(FileHandle, Command, BriefDesc, &BriefSize, &Ascii); + if (!EFI_ERROR(Status) && HelpText != NULL){ + Status = ManFileFindSections(FileHandle, Sections, HelpText, &HelpSize, Ascii); + } + ShellInfoObject.NewEfiShellProtocol->CloseFile(FileHandle); + if (!EFI_ERROR(Status)) { + // + // Get help text from .MAN file success. + // + goto Done; + } + } + + // + // Load the app image to check EFI_HII_PACKAGE_LIST_PROTOCOL. + // + CmdFileName = GetExecuatableFileName(TempString); + if (CmdFileName == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + // + // If the file in CWD then use the file name, else use the full + // path name. + // + CmdFilePathName = ShellFindFilePath(CmdFileName); + if (CmdFilePathName == NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + DevPath = ShellInfoObject.NewEfiShellProtocol->GetDevicePathFromFilePath(CmdFilePathName); + Status = gBS->LoadImage(FALSE, gImageHandle, DevPath, NULL, 0, &CmdFileImgHandle); + if(EFI_ERROR(Status)) { + // + // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created + // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now. + // If the caller doesn't have the option to defer the execution of an image, we should + // unload image for the EFI_SECURITY_VIOLATION to avoid the resource leak. + // + if (Status == EFI_SECURITY_VIOLATION) { + gBS->UnloadImage (CmdFileImgHandle); + } + *HelpText = NULL; + goto Done; + } + Status = gBS->OpenProtocol( + CmdFileImgHandle, + &gEfiHiiPackageListProtocolGuid, + (VOID**)&PackageListHeader, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if(EFI_ERROR(Status)) { + *HelpText = NULL; + goto Done; + } + + // + // If get package list on image handle, install it on HiiDatabase. + // + Status = gBS->InstallProtocolInterface ( + &mShellManDriverHandle, + &gEfiDevicePathProtocolGuid, + EFI_NATIVE_INTERFACE, + &mShellManHiiDevicePath + ); + if (EFI_ERROR(Status)) { + goto Done; + } + + Status = gHiiDatabase->NewPackageList ( + gHiiDatabase, + PackageListHeader, + mShellManDriverHandle, + &mShellManHiiHandle + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + StringIdWalker = 1; + do { + SHELL_FREE_NON_NULL(TempString); + if (BriefDesc != NULL) { + SHELL_FREE_NON_NULL(*BriefDesc); + } + TempString = HiiGetString (mShellManHiiHandle, (EFI_STRING_ID)StringIdWalker, NULL); + if (TempString == NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + FileHandle = ConvertEfiFileProtocolToShellHandle (CreateFileInterfaceMem (TRUE), NULL); + HelpSize = StrLen (TempString) * sizeof (CHAR16); + ShellWriteFile (FileHandle, &HelpSize, TempString); + ShellSetFilePosition (FileHandle, 0); + HelpSize = 0; + BriefSize = 0; + Status = ManFileFindTitleSection(FileHandle, Command, BriefDesc, &BriefSize, &Ascii); + if (!EFI_ERROR(Status) && HelpText != NULL){ + Status = ManFileFindSections(FileHandle, Sections, HelpText, &HelpSize, Ascii); + } + ShellCloseFile (&FileHandle); + if (!EFI_ERROR(Status)){ + // + // Found what we need and return + // + goto Done; + } + + StringIdWalker += 1; + } while (StringIdWalker < 0xFFFF && TempString != NULL); + + } + +Done: + if (mShellManDriverHandle != NULL) { + gBS->UninstallProtocolInterface ( + mShellManDriverHandle, + &gEfiDevicePathProtocolGuid, + &mShellManHiiDevicePath + ); + mShellManDriverHandle = NULL; + } + + if (mShellManHiiHandle != NULL) { + HiiRemovePackages (mShellManHiiHandle); + mShellManHiiHandle = NULL; + } + + if (CmdFileImgHandle != NULL) { + Status = gBS->UnloadImage (CmdFileImgHandle); + } + + SHELL_FREE_NON_NULL(TempString); + SHELL_FREE_NON_NULL(CmdFileName); + SHELL_FREE_NON_NULL(CmdFilePathName); + SHELL_FREE_NON_NULL(FileDevPath); + SHELL_FREE_NON_NULL(DevPath); + + return (Status); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellManParser.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellManParser.h new file mode 100644 index 00000000..59fcf4c9 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellManParser.h @@ -0,0 +1,78 @@ +/** @file + Provides interface to shell MAN file parser. + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SHELL_MAN_FILE_PARSER_HEADER_ +#define _SHELL_MAN_FILE_PARSER_HEADER_ + +/** + This function returns the help information for the specified command. The help text + will be parsed from a UEFI Shell manual page. (see UEFI Shell 2.0 Appendix B) + + If Sections is specified, then each section name listed will be compared in a casesensitive + manner, to the section names described in Appendix B. If the section exists, + it will be appended to the returned help text. If the section does not exist, no + information will be returned. If Sections is NULL, then all help text information + available will be returned. + + if BriefDesc is NULL, then the breif description will not be savedd separately, + but placed first in the main HelpText. + + @param[in] ManFileName Points to the NULL-terminated UEFI Shell MAN file name. + @param[in] Command Points to the NULL-terminated UEFI Shell command name. + @param[in] Sections Points to the NULL-terminated comma-delimited + section names to return. If NULL, then all + sections will be returned. + @param[out] BriefDesc On return, points to a callee-allocated buffer + containing brief description text. + @param[out] HelpText On return, points to a callee-allocated buffer + containing all specified help text. + + @retval EFI_SUCCESS The help text was returned. + @retval EFI_OUT_OF_RESOURCES The necessary buffer could not be allocated to hold the + returned help text. + @retval EFI_INVALID_PARAMETER HelpText is NULL + @retval EFI_NOT_FOUND There is no help text available for Command. +**/ +EFI_STATUS +ProcessManFile( + IN CONST CHAR16 *ManFileName, + IN CONST CHAR16 *Command, + IN CONST CHAR16 *Sections OPTIONAL, + OUT CHAR16 **BriefDesc, + OUT CHAR16 **HelpText + ); + +/** + parses through the MAN file specified by SHELL_FILE_HANDLE and returns the + detailed help for any sub section specified in the comma separated list of + sections provided. If the end of the file or a .TH section is found then + return. + + Upon a successful return the caller is responsible to free the memory in *HelpText + + @param[in] Handle FileHandle to read from + @param[in] Sections name of command's sub sections to find + @param[out] HelpText pointer to pointer to string where text goes. + @param[out] HelpSize pointer to size of allocated HelpText (may be updated) + @param[in] Ascii TRUE if the file is ASCII, FALSE otherwise. + + @retval EFI_OUT_OF_RESOURCES a memory allocation failed. + @retval EFI_SUCCESS the section was found and its description stored in + an allocated buffer. +**/ +EFI_STATUS +ManFileFindSections( + IN SHELL_FILE_HANDLE Handle, + IN CONST CHAR16 *Sections, + OUT CHAR16 **HelpText, + OUT UINTN *HelpSize, + IN BOOLEAN Ascii + ); + +#endif //_SHELL_MAN_FILE_PARSER_HEADER_ + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellParametersProtocol.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellParametersProtocol.c new file mode 100644 index 00000000..54509e88 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellParametersProtocol.c @@ -0,0 +1,1414 @@ +/** @file + Member functions of EFI_SHELL_PARAMETERS_PROTOCOL and functions for creation, + manipulation, and initialization of EFI_SHELL_PARAMETERS_PROTOCOL. + + (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+ Copyright (C) 2014, Red Hat, Inc. + (C) Copyright 2013 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Shell.h" + +BOOLEAN AsciiRedirection = FALSE; + +/** + Return the next parameter's end from a command line string. + + @param[in] String the string to parse +**/ +CONST CHAR16* +FindEndOfParameter( + IN CONST CHAR16 *String + ) +{ + CONST CHAR16 *First; + CONST CHAR16 *CloseQuote; + + First = FindFirstCharacter(String, L" \"", L'^'); + + // + // nothing, all one parameter remaining + // + if (*First == CHAR_NULL) { + return (First); + } + + // + // If space before a quote (or neither found, i.e. both CHAR_NULL), + // then that's the end. + // + if (*First == L' ') { + return (First); + } + + CloseQuote = FindFirstCharacter (First+1, L"\"", L'^'); + + // + // We did not find a terminator... + // + if (*CloseQuote == CHAR_NULL) { + return (NULL); + } + + return (FindEndOfParameter (CloseQuote+1)); +} + +/** + Return the next parameter from a command line string. + + This function moves the next parameter from Walker into TempParameter and moves + Walker up past that parameter for recursive calling. When the final parameter + is moved *Walker will be set to NULL; + + Temp Parameter must be large enough to hold the parameter before calling this + function. + + This will also remove all remaining ^ characters after processing. + + @param[in, out] Walker pointer to string of command line. Adjusted to + remaining command line on return + @param[in, out] TempParameter pointer to string of command line item extracted. + @param[in] Length buffer size of TempParameter. + @param[in] StripQuotation if TRUE then strip the quotation marks surrounding + the parameters. + + @return EFI_INVALID_PARAMETER A required parameter was NULL or pointed to a NULL or empty string. + @return EFI_NOT_FOUND A closing " could not be found on the specified string +**/ +EFI_STATUS +GetNextParameter( + IN OUT CHAR16 **Walker, + IN OUT CHAR16 **TempParameter, + IN CONST UINTN Length, + IN BOOLEAN StripQuotation + ) +{ + CONST CHAR16 *NextDelim; + + if (Walker == NULL + ||*Walker == NULL + ||TempParameter == NULL + ||*TempParameter == NULL + ){ + return (EFI_INVALID_PARAMETER); + } + + + // + // make sure we dont have any leading spaces + // + while ((*Walker)[0] == L' ') { + (*Walker)++; + } + + // + // make sure we still have some params now... + // + if (StrLen(*Walker) == 0) { +DEBUG_CODE_BEGIN(); + *Walker = NULL; +DEBUG_CODE_END(); + return (EFI_INVALID_PARAMETER); + } + + NextDelim = FindEndOfParameter(*Walker); + + if (NextDelim == NULL){ +DEBUG_CODE_BEGIN(); + *Walker = NULL; +DEBUG_CODE_END(); + return (EFI_NOT_FOUND); + } + + StrnCpyS(*TempParameter, Length / sizeof(CHAR16), (*Walker), NextDelim - *Walker); + + // + // Add a CHAR_NULL if we didn't get one via the copy + // + if (*NextDelim != CHAR_NULL) { + (*TempParameter)[NextDelim - *Walker] = CHAR_NULL; + } + + // + // Update Walker for the next iteration through the function + // + *Walker = (CHAR16*)NextDelim; + + // + // Remove any non-escaped quotes in the string + // Remove any remaining escape characters in the string + // + for (NextDelim = FindFirstCharacter(*TempParameter, L"\"^", CHAR_NULL) + ; *NextDelim != CHAR_NULL + ; NextDelim = FindFirstCharacter(NextDelim, L"\"^", CHAR_NULL) + ) { + if (*NextDelim == L'^') { + + // + // eliminate the escape ^ + // + CopyMem ((CHAR16*)NextDelim, NextDelim + 1, StrSize (NextDelim + 1)); + NextDelim++; + } else if (*NextDelim == L'\"') { + + // + // eliminate the unescaped quote + // + if (StripQuotation) { + CopyMem ((CHAR16*)NextDelim, NextDelim + 1, StrSize (NextDelim + 1)); + } else{ + NextDelim++; + } + } + } + + return EFI_SUCCESS; +} + +/** + Function to populate Argc and Argv. + + This function parses the CommandLine and divides it into standard C style Argc/Argv + parameters for inclusion in EFI_SHELL_PARAMETERS_PROTOCOL. this supports space + delimited and quote surrounded parameter definition. + + All special character processing (alias, environment variable, redirection, + etc... must be complete before calling this API. + + @param[in] CommandLine String of command line to parse + @param[in] StripQuotation if TRUE then strip the quotation marks surrounding + the parameters. + @param[in, out] Argv pointer to array of strings; one for each parameter + @param[in, out] Argc pointer to number of strings in Argv array + + @return EFI_SUCCESS the operation was successful + @return EFI_INVALID_PARAMETER some parameters are invalid + @return EFI_OUT_OF_RESOURCES a memory allocation failed. +**/ +EFI_STATUS +ParseCommandLineToArgs( + IN CONST CHAR16 *CommandLine, + IN BOOLEAN StripQuotation, + IN OUT CHAR16 ***Argv, + IN OUT UINTN *Argc + ) +{ + UINTN Count; + CHAR16 *TempParameter; + CHAR16 *Walker; + CHAR16 *NewParam; + CHAR16 *NewCommandLine; + UINTN Size; + EFI_STATUS Status; + + ASSERT(Argc != NULL); + ASSERT(Argv != NULL); + + if (CommandLine == NULL || StrLen(CommandLine)==0) { + (*Argc) = 0; + (*Argv) = NULL; + return (EFI_SUCCESS); + } + + NewCommandLine = AllocateCopyPool(StrSize(CommandLine), CommandLine); + if (NewCommandLine == NULL){ + return (EFI_OUT_OF_RESOURCES); + } + + TrimSpaces(&NewCommandLine); + Size = StrSize(NewCommandLine); + TempParameter = AllocateZeroPool(Size); + if (TempParameter == NULL) { + SHELL_FREE_NON_NULL(NewCommandLine); + return (EFI_OUT_OF_RESOURCES); + } + + for ( Count = 0 + , Walker = (CHAR16*)NewCommandLine + ; Walker != NULL && *Walker != CHAR_NULL + ; Count++ + ) { + if (EFI_ERROR(GetNextParameter(&Walker, &TempParameter, Size, TRUE))) { + break; + } + } + + // + // lets allocate the pointer array + // + (*Argv) = AllocateZeroPool((Count)*sizeof(CHAR16*)); + if (*Argv == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + *Argc = 0; + Walker = (CHAR16*)NewCommandLine; + while(Walker != NULL && *Walker != CHAR_NULL) { + SetMem16(TempParameter, Size, CHAR_NULL); + if (EFI_ERROR(GetNextParameter(&Walker, &TempParameter, Size, StripQuotation))) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + NewParam = AllocateCopyPool(StrSize(TempParameter), TempParameter); + if (NewParam == NULL){ + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + ((CHAR16**)(*Argv))[(*Argc)] = NewParam; + (*Argc)++; + } + ASSERT(Count >= (*Argc)); + Status = EFI_SUCCESS; + +Done: + SHELL_FREE_NON_NULL(TempParameter); + SHELL_FREE_NON_NULL(NewCommandLine); + return (Status); +} + +/** + creates a new EFI_SHELL_PARAMETERS_PROTOCOL instance and populates it and then + installs it on our handle and if there is an existing version of the protocol + that one is cached for removal later. + + @param[in, out] NewShellParameters on a successful return, a pointer to pointer + to the newly installed interface. + @param[in, out] RootShellInstance on a successful return, pointer to boolean. + TRUE if this is the root shell instance. + + @retval EFI_SUCCESS the operation completed successfully. + @return other the operation failed. + @sa ReinstallProtocolInterface + @sa InstallProtocolInterface + @sa ParseCommandLineToArgs +**/ +EFI_STATUS +CreatePopulateInstallShellParametersProtocol ( + IN OUT EFI_SHELL_PARAMETERS_PROTOCOL **NewShellParameters, + IN OUT BOOLEAN *RootShellInstance + ) +{ + EFI_STATUS Status; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + CHAR16 *FullCommandLine; + UINTN Size; + + Size = 0; + FullCommandLine = NULL; + LoadedImage = NULL; + + // + // Assert for valid parameters + // + ASSERT(NewShellParameters != NULL); + ASSERT(RootShellInstance != NULL); + + // + // See if we have a shell parameters placed on us + // + Status = gBS->OpenProtocol ( + gImageHandle, + &gEfiShellParametersProtocolGuid, + (VOID **) &ShellInfoObject.OldShellParameters, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + // + // if we don't then we must be the root shell (error is expected) + // + if (EFI_ERROR (Status)) { + *RootShellInstance = TRUE; + } + + // + // Allocate the new structure + // + *NewShellParameters = AllocateZeroPool(sizeof(EFI_SHELL_PARAMETERS_PROTOCOL)); + if ((*NewShellParameters) == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + // + // get loaded image protocol + // + Status = gBS->OpenProtocol ( + gImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID **) &LoadedImage, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + ASSERT_EFI_ERROR(Status); + // + // Build the full command line + // + Status = SHELL_GET_ENVIRONMENT_VARIABLE(L"ShellOpt", &Size, FullCommandLine); + if (Status == EFI_BUFFER_TOO_SMALL) { + FullCommandLine = AllocateZeroPool(Size + LoadedImage->LoadOptionsSize); + Status = SHELL_GET_ENVIRONMENT_VARIABLE(L"ShellOpt", &Size, FullCommandLine); + } + if (Status == EFI_NOT_FOUND) { + // + // no parameters via environment... ok + // + } else { + if (EFI_ERROR(Status)) { + return (Status); + } + } + if (Size == 0 && LoadedImage->LoadOptionsSize != 0) { + ASSERT(FullCommandLine == NULL); + // + // Now we need to include a NULL terminator in the size. + // + Size = LoadedImage->LoadOptionsSize + sizeof(FullCommandLine[0]); + FullCommandLine = AllocateZeroPool(Size); + } + if (FullCommandLine != NULL) { + CopyMem (FullCommandLine, LoadedImage->LoadOptions, LoadedImage->LoadOptionsSize); + // + // Populate Argc and Argv + // + Status = ParseCommandLineToArgs(FullCommandLine, + TRUE, + &(*NewShellParameters)->Argv, + &(*NewShellParameters)->Argc); + + FreePool(FullCommandLine); + + ASSERT_EFI_ERROR(Status); + } else { + (*NewShellParameters)->Argv = NULL; + (*NewShellParameters)->Argc = 0; + } + + // + // Populate the 3 faked file systems... + // + if (*RootShellInstance) { + (*NewShellParameters)->StdIn = &FileInterfaceStdIn; + (*NewShellParameters)->StdOut = &FileInterfaceStdOut; + (*NewShellParameters)->StdErr = &FileInterfaceStdErr; + Status = gBS->InstallProtocolInterface(&gImageHandle, + &gEfiShellParametersProtocolGuid, + EFI_NATIVE_INTERFACE, + (VOID*)(*NewShellParameters)); + } else { + // + // copy from the existing ones + // + (*NewShellParameters)->StdIn = ShellInfoObject.OldShellParameters->StdIn; + (*NewShellParameters)->StdOut = ShellInfoObject.OldShellParameters->StdOut; + (*NewShellParameters)->StdErr = ShellInfoObject.OldShellParameters->StdErr; + Status = gBS->ReinstallProtocolInterface(gImageHandle, + &gEfiShellParametersProtocolGuid, + (VOID*)ShellInfoObject.OldShellParameters, + (VOID*)(*NewShellParameters)); + } + + return (Status); +} + +/** + frees all memory used by creation and installation of shell parameters protocol + and if there was an old version installed it will restore that one. + + @param NewShellParameters the interface of EFI_SHELL_PARAMETERS_PROTOCOL that is + being cleaned up. + + @retval EFI_SUCCESS the cleanup was successful + @return other the cleanup failed + @sa ReinstallProtocolInterface + @sa UninstallProtocolInterface +**/ +EFI_STATUS +CleanUpShellParametersProtocol ( + IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *NewShellParameters + ) +{ + EFI_STATUS Status; + UINTN LoopCounter; + + // + // If the old exists we need to restore it + // + if (ShellInfoObject.OldShellParameters != NULL) { + Status = gBS->ReinstallProtocolInterface(gImageHandle, + &gEfiShellParametersProtocolGuid, + (VOID*)NewShellParameters, + (VOID*)ShellInfoObject.OldShellParameters); + DEBUG_CODE(ShellInfoObject.OldShellParameters = NULL;); + } else { + // + // No old one, just uninstall us... + // + Status = gBS->UninstallProtocolInterface(gImageHandle, + &gEfiShellParametersProtocolGuid, + (VOID*)NewShellParameters); + } + if (NewShellParameters->Argv != NULL) { + for ( LoopCounter = 0 + ; LoopCounter < NewShellParameters->Argc + ; LoopCounter++ + ){ + FreePool(NewShellParameters->Argv[LoopCounter]); + } + FreePool(NewShellParameters->Argv); + } + FreePool(NewShellParameters); + return (Status); +} + +/** + Determine if a file name represents a unicode file. + + @param[in] FileName Pointer to the filename to open. + + @retval EFI_SUCCESS The file is a unicode file. + @return An error upon failure. +**/ +EFI_STATUS +IsUnicodeFile( + IN CONST CHAR16 *FileName + ) +{ + SHELL_FILE_HANDLE Handle; + EFI_STATUS Status; + UINT64 OriginalFilePosition; + UINTN CharSize; + CHAR16 CharBuffer; + + Status = gEfiShellProtocol->OpenFileByName(FileName, &Handle, EFI_FILE_MODE_READ); + if (EFI_ERROR(Status)) { + return (Status); + } + gEfiShellProtocol->GetFilePosition(Handle, &OriginalFilePosition); + gEfiShellProtocol->SetFilePosition(Handle, 0); + CharSize = sizeof(CHAR16); + Status = gEfiShellProtocol->ReadFile(Handle, &CharSize, &CharBuffer); + if (EFI_ERROR(Status) || CharBuffer != gUnicodeFileTag) { + Status = EFI_BUFFER_TOO_SMALL; + } + gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition); + gEfiShellProtocol->CloseFile(Handle); + return (Status); +} + +/** + Strips out quotes sections of a string. + + All of the characters between quotes is replaced with spaces. + + @param[in, out] TheString A pointer to the string to update. +**/ +VOID +StripQuotes ( + IN OUT CHAR16 *TheString + ) +{ + BOOLEAN RemoveNow; + + for (RemoveNow = FALSE ; TheString != NULL && *TheString != CHAR_NULL ; TheString++) { + if (*TheString == L'^' && *(TheString + 1) == L'\"') { + TheString++; + } else if (*TheString == L'\"') { + RemoveNow = (BOOLEAN)!RemoveNow; + } else if (RemoveNow) { + *TheString = L' '; + } + } +} + +/** + Calculate the 32-bit CRC in a EFI table using the service provided by the + gRuntime service. + + @param Hdr Pointer to an EFI standard header + +**/ +VOID +CalculateEfiHdrCrc ( + IN OUT EFI_TABLE_HEADER *Hdr + ) +{ + UINT32 Crc; + + Hdr->CRC32 = 0; + + // + // If gBS->CalculateCrce32 () == CoreEfiNotAvailableYet () then + // Crc will come back as zero if we set it to zero here + // + Crc = 0; + gBS->CalculateCrc32 ((UINT8 *)Hdr, Hdr->HeaderSize, &Crc); + Hdr->CRC32 = Crc; +} + +/** + Fix a string to only have the file name, removing starting at the first space of whatever is quoted. + + @param[in] FileName The filename to start with. + + @retval NULL FileName was invalid. + @return The modified FileName. +**/ +CHAR16* +FixFileName ( + IN CHAR16 *FileName + ) +{ + CHAR16 *Copy; + CHAR16 *TempLocation; + + if (FileName == NULL) { + return (NULL); + } + + if (FileName[0] == L'\"') { + Copy = FileName+1; + if ((TempLocation = StrStr(Copy , L"\"")) != NULL) { + TempLocation[0] = CHAR_NULL; + } + } else { + Copy = FileName; + while(Copy[0] == L' ') { + Copy++; + } + if ((TempLocation = StrStr(Copy , L" ")) != NULL) { + TempLocation[0] = CHAR_NULL; + } + } + + if (Copy[0] == CHAR_NULL) { + return (NULL); + } + + return (Copy); +} + +/** + Fix a string to only have the environment variable name, removing starting at the first space of whatever is quoted and removing the leading and trailing %. + + @param[in] FileName The filename to start with. + + @retval NULL FileName was invalid. + @return The modified FileName. +**/ +CHAR16* +FixVarName ( + IN CHAR16 *FileName + ) +{ + CHAR16 *Copy; + CHAR16 *TempLocation; + + Copy = FileName; + + if (FileName[0] == L'%') { + Copy = FileName+1; + if ((TempLocation = StrStr(Copy , L"%")) != NULL) { + TempLocation[0] = CHAR_NULL; + } + } + + return (FixFileName(Copy)); +} + + +/** + Write the unicode file tag to the specified file. + + It is the caller's responsibility to ensure that + ShellInfoObject.NewEfiShellProtocol has been initialized before calling this + function. + + @param[in] FileHandle The file to write the unicode file tag to. + + @return Status code from ShellInfoObject.NewEfiShellProtocol->WriteFile. +**/ +EFI_STATUS +WriteFileTag ( + IN SHELL_FILE_HANDLE FileHandle + ) +{ + CHAR16 FileTag; + UINTN Size; + EFI_STATUS Status; + + FileTag = gUnicodeFileTag; + Size = sizeof FileTag; + Status = ShellInfoObject.NewEfiShellProtocol->WriteFile (FileHandle, &Size, + &FileTag); + ASSERT (EFI_ERROR (Status) || Size == sizeof FileTag); + return Status; +} + + +/** + Function will replace the current StdIn and StdOut in the ShellParameters protocol + structure by parsing NewCommandLine. The current values are returned to the + user. + + This will also update the system table. + + @param[in, out] ShellParameters Pointer to parameter structure to modify. + @param[in] NewCommandLine The new command line to parse and use. + @param[out] OldStdIn Pointer to old StdIn. + @param[out] OldStdOut Pointer to old StdOut. + @param[out] OldStdErr Pointer to old StdErr. + @param[out] SystemTableInfo Pointer to old system table information. + + @retval EFI_SUCCESS Operation was successful, Argv and Argc are valid. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +UpdateStdInStdOutStdErr( + IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters, + IN CHAR16 *NewCommandLine, + OUT SHELL_FILE_HANDLE *OldStdIn, + OUT SHELL_FILE_HANDLE *OldStdOut, + OUT SHELL_FILE_HANDLE *OldStdErr, + OUT SYSTEM_TABLE_INFO *SystemTableInfo + ) +{ + CHAR16 *CommandLineCopy; + CHAR16 *CommandLineWalker; + CHAR16 *StdErrFileName; + CHAR16 *StdOutFileName; + CHAR16 *StdInFileName; + CHAR16 *StdInVarName; + CHAR16 *StdOutVarName; + CHAR16 *StdErrVarName; + EFI_STATUS Status; + SHELL_FILE_HANDLE TempHandle; + UINT64 FileSize; + BOOLEAN OutUnicode; + BOOLEAN InUnicode; + BOOLEAN ErrUnicode; + BOOLEAN OutAppend; + BOOLEAN ErrAppend; + UINTN Size; + SPLIT_LIST *Split; + CHAR16 *FirstLocation; + BOOLEAN Volatile; + + OutUnicode = TRUE; + InUnicode = TRUE; + AsciiRedirection = FALSE; + ErrUnicode = TRUE; + StdInVarName = NULL; + StdOutVarName = NULL; + StdErrVarName = NULL; + StdErrFileName = NULL; + StdInFileName = NULL; + StdOutFileName = NULL; + ErrAppend = FALSE; + OutAppend = FALSE; + CommandLineCopy = NULL; + FirstLocation = NULL; + + if (ShellParameters == NULL || SystemTableInfo == NULL || OldStdIn == NULL || OldStdOut == NULL || OldStdErr == NULL) { + return (EFI_INVALID_PARAMETER); + } + + SystemTableInfo->ConIn = gST->ConIn; + SystemTableInfo->ConInHandle = gST->ConsoleInHandle; + SystemTableInfo->ConOut = gST->ConOut; + SystemTableInfo->ConOutHandle = gST->ConsoleOutHandle; + SystemTableInfo->ErrOut = gST->StdErr; + SystemTableInfo->ErrOutHandle = gST->StandardErrorHandle; + *OldStdIn = ShellParameters->StdIn; + *OldStdOut = ShellParameters->StdOut; + *OldStdErr = ShellParameters->StdErr; + + if (NewCommandLine == NULL) { + return (EFI_SUCCESS); + } + + CommandLineCopy = StrnCatGrow(&CommandLineCopy, NULL, NewCommandLine, 0); + if (CommandLineCopy == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + Status = EFI_SUCCESS; + Split = NULL; + FirstLocation = CommandLineCopy + StrLen(CommandLineCopy); + + StripQuotes(CommandLineCopy); + + if (!IsListEmpty(&ShellInfoObject.SplitList.Link)) { + Split = (SPLIT_LIST*)GetFirstNode(&ShellInfoObject.SplitList.Link); + if (Split != NULL && Split->SplitStdIn != NULL) { + ShellParameters->StdIn = Split->SplitStdIn; + } + if (Split != NULL && Split->SplitStdOut != NULL) { + ShellParameters->StdOut = Split->SplitStdOut; + } + } + + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 2>>v ")) != NULL) { + FirstLocation = MIN(CommandLineWalker, FirstLocation); + SetMem16(CommandLineWalker, 12, L' '); + StdErrVarName = CommandLineWalker += 6; + ErrAppend = TRUE; + if (StrStr(CommandLineWalker, L" 2>>v ") != NULL) { + Status = EFI_NOT_FOUND; + } + } + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 1>>v ")) != NULL) { + FirstLocation = MIN(CommandLineWalker, FirstLocation); + SetMem16(CommandLineWalker, 12, L' '); + StdOutVarName = CommandLineWalker += 6; + OutAppend = TRUE; + if (StrStr(CommandLineWalker, L" 1>>v ") != NULL) { + Status = EFI_NOT_FOUND; + } + } else if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" >>v ")) != NULL) { + FirstLocation = MIN(CommandLineWalker, FirstLocation); + SetMem16(CommandLineWalker, 10, L' '); + StdOutVarName = CommandLineWalker += 5; + OutAppend = TRUE; + if (StrStr(CommandLineWalker, L" >>v ") != NULL) { + Status = EFI_NOT_FOUND; + } + } else if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" >v ")) != NULL) { + FirstLocation = MIN(CommandLineWalker, FirstLocation); + SetMem16(CommandLineWalker, 8, L' '); + StdOutVarName = CommandLineWalker += 4; + OutAppend = FALSE; + if (StrStr(CommandLineWalker, L" >v ") != NULL) { + Status = EFI_NOT_FOUND; + } + } + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 1>>a ")) != NULL) { + FirstLocation = MIN(CommandLineWalker, FirstLocation); + SetMem16(CommandLineWalker, 12, L' '); + StdOutFileName = CommandLineWalker += 6; + OutAppend = TRUE; + OutUnicode = FALSE; + if (StrStr(CommandLineWalker, L" 1>>a ") != NULL) { + Status = EFI_NOT_FOUND; + } + } + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 1>> ")) != NULL) { + FirstLocation = MIN(CommandLineWalker, FirstLocation); + SetMem16(CommandLineWalker, 10, L' '); + if (StdOutFileName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdOutFileName = CommandLineWalker += 5; + OutAppend = TRUE; + } + if (StrStr(CommandLineWalker, L" 1>> ") != NULL) { + Status = EFI_NOT_FOUND; + } + } + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" >> ")) != NULL) { + FirstLocation = MIN(CommandLineWalker, FirstLocation); + SetMem16(CommandLineWalker, 8, L' '); + if (StdOutFileName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdOutFileName = CommandLineWalker += 4; + OutAppend = TRUE; + } + if (StrStr(CommandLineWalker, L" >> ") != NULL) { + Status = EFI_NOT_FOUND; + } + } + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" >>a ")) != NULL) { + FirstLocation = MIN(CommandLineWalker, FirstLocation); + SetMem16(CommandLineWalker, 10, L' '); + if (StdOutFileName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdOutFileName = CommandLineWalker += 5; + OutAppend = TRUE; + OutUnicode = FALSE; + } + if (StrStr(CommandLineWalker, L" >>a ") != NULL) { + Status = EFI_NOT_FOUND; + } + } + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 1>a ")) != NULL) { + FirstLocation = MIN(CommandLineWalker, FirstLocation); + SetMem16(CommandLineWalker, 10, L' '); + if (StdOutFileName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdOutFileName = CommandLineWalker += 5; + OutAppend = FALSE; + OutUnicode = FALSE; + } + if (StrStr(CommandLineWalker, L" 1>a ") != NULL) { + Status = EFI_NOT_FOUND; + } + } + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" >a ")) != NULL) { + FirstLocation = MIN(CommandLineWalker, FirstLocation); + SetMem16(CommandLineWalker, 8, L' '); + if (StdOutFileName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdOutFileName = CommandLineWalker += 4; + OutAppend = FALSE; + OutUnicode = FALSE; + } + if (StrStr(CommandLineWalker, L" >a ") != NULL) { + Status = EFI_NOT_FOUND; + } + } + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 2>> ")) != NULL) { + FirstLocation = MIN(CommandLineWalker, FirstLocation); + SetMem16(CommandLineWalker, 10, L' '); + if (StdErrFileName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdErrFileName = CommandLineWalker += 5; + ErrAppend = TRUE; + } + if (StrStr(CommandLineWalker, L" 2>> ") != NULL) { + Status = EFI_NOT_FOUND; + } + } + + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 2>v ")) != NULL) { + FirstLocation = MIN(CommandLineWalker, FirstLocation); + SetMem16(CommandLineWalker, 10, L' '); + if (StdErrVarName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdErrVarName = CommandLineWalker += 5; + ErrAppend = FALSE; + } + if (StrStr(CommandLineWalker, L" 2>v ") != NULL) { + Status = EFI_NOT_FOUND; + } + } + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 1>v ")) != NULL) { + FirstLocation = MIN(CommandLineWalker, FirstLocation); + SetMem16(CommandLineWalker, 10, L' '); + if (StdOutVarName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdOutVarName = CommandLineWalker += 5; + OutAppend = FALSE; + } + if (StrStr(CommandLineWalker, L" 1>v ") != NULL) { + Status = EFI_NOT_FOUND; + } + } + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 2>a ")) != NULL) { + FirstLocation = MIN(CommandLineWalker, FirstLocation); + SetMem16(CommandLineWalker, 10, L' '); + if (StdErrFileName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdErrFileName = CommandLineWalker += 5; + ErrAppend = FALSE; + ErrUnicode = FALSE; + } + if (StrStr(CommandLineWalker, L" 2>a ") != NULL) { + Status = EFI_NOT_FOUND; + } + } + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 2> ")) != NULL) { + FirstLocation = MIN(CommandLineWalker, FirstLocation); + SetMem16(CommandLineWalker, 8, L' '); + if (StdErrFileName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdErrFileName = CommandLineWalker += 4; + ErrAppend = FALSE; + } + if (StrStr(CommandLineWalker, L" 2> ") != NULL) { + Status = EFI_NOT_FOUND; + } + } + + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 1> ")) != NULL) { + FirstLocation = MIN(CommandLineWalker, FirstLocation); + SetMem16(CommandLineWalker, 8, L' '); + if (StdOutFileName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdOutFileName = CommandLineWalker += 4; + OutAppend = FALSE; + } + if (StrStr(CommandLineWalker, L" 1> ") != NULL) { + Status = EFI_NOT_FOUND; + } + } + + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" > ")) != NULL) { + FirstLocation = MIN(CommandLineWalker, FirstLocation); + SetMem16(CommandLineWalker, 6, L' '); + if (StdOutFileName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdOutFileName = CommandLineWalker += 3; + OutAppend = FALSE; + } + if (StrStr(CommandLineWalker, L" > ") != NULL) { + Status = EFI_NOT_FOUND; + } + } + + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" < ")) != NULL) { + FirstLocation = MIN(CommandLineWalker, FirstLocation); + SetMem16(CommandLineWalker, 6, L' '); + if (StdInFileName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdInFileName = CommandLineWalker += 3; + } + if (StrStr(CommandLineWalker, L" < ") != NULL) { + Status = EFI_NOT_FOUND; + } + } + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" SplitStdIn != NULL && (StdInVarName != NULL || StdInFileName != NULL)) + ||(Split != NULL && Split->SplitStdOut != NULL && (StdOutVarName != NULL || StdOutFileName != NULL)) + // + // Check that nothing is trying to be output to 2 locations. + // + ||(StdErrFileName != NULL && StdErrVarName != NULL) + ||(StdOutFileName != NULL && StdOutVarName != NULL) + ||(StdInFileName != NULL && StdInVarName != NULL) + // + // Check for no volatile environment variables + // + ||(StdErrVarName != NULL && !EFI_ERROR (IsVolatileEnv (StdErrVarName, &Volatile)) && !Volatile) + ||(StdOutVarName != NULL && !EFI_ERROR (IsVolatileEnv (StdOutVarName, &Volatile)) && !Volatile) + // + // Cant redirect during a reconnect operation. + // + ||(StrStr(NewCommandLine, L"connect -r") != NULL + && (StdOutVarName != NULL || StdOutFileName != NULL || StdErrFileName != NULL || StdErrVarName != NULL)) + // + // Check that filetypes (Unicode/Ascii) do not change during an append + // + ||(StdOutFileName != NULL && OutUnicode && OutAppend && (!EFI_ERROR(ShellFileExists(StdOutFileName)) && EFI_ERROR(IsUnicodeFile(StdOutFileName)))) + ||(StdErrFileName != NULL && ErrUnicode && ErrAppend && (!EFI_ERROR(ShellFileExists(StdErrFileName)) && EFI_ERROR(IsUnicodeFile(StdErrFileName)))) + ||(StdOutFileName != NULL && !OutUnicode && OutAppend && (!EFI_ERROR(ShellFileExists(StdOutFileName)) && !EFI_ERROR(IsUnicodeFile(StdOutFileName)))) + ||(StdErrFileName != NULL && !ErrUnicode && ErrAppend && (!EFI_ERROR(ShellFileExists(StdErrFileName)) && !EFI_ERROR(IsUnicodeFile(StdErrFileName)))) + ){ + Status = EFI_INVALID_PARAMETER; + ShellParameters->StdIn = *OldStdIn; + ShellParameters->StdOut = *OldStdOut; + ShellParameters->StdErr = *OldStdErr; + } else if (!EFI_ERROR(Status)){ + // + // Open the Std and we should not have conflicts here... + // + + // + // StdErr to a file + // + if (StdErrFileName != NULL) { + if (!ErrAppend) { + // + // delete existing file. + // + ShellInfoObject.NewEfiShellProtocol->DeleteFileByName(StdErrFileName); + } + Status = ShellOpenFileByName(StdErrFileName, &TempHandle, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ|EFI_FILE_MODE_CREATE,0); + if (!ErrAppend && ErrUnicode && !EFI_ERROR(Status)) { + Status = WriteFileTag (TempHandle); + } + if (!ErrUnicode && !EFI_ERROR(Status)) { + TempHandle = CreateFileInterfaceFile(TempHandle, FALSE); + ASSERT(TempHandle != NULL); + } + if (!EFI_ERROR(Status)) { + ShellParameters->StdErr = TempHandle; + gST->StdErr = CreateSimpleTextOutOnFile(TempHandle, &gST->StandardErrorHandle, gST->StdErr); + } + } + + // + // StdOut to a file + // + if (!EFI_ERROR(Status) && StdOutFileName != NULL) { + if (!OutAppend) { + // + // delete existing file. + // + ShellInfoObject.NewEfiShellProtocol->DeleteFileByName(StdOutFileName); + } + Status = ShellOpenFileByName(StdOutFileName, &TempHandle, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ|EFI_FILE_MODE_CREATE,0); + if (TempHandle == NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + if (gUnicodeCollation->MetaiMatch (gUnicodeCollation, StdOutFileName, L"NUL")) { + //no-op + } else if (!OutAppend && OutUnicode && !EFI_ERROR(Status)) { + Status = WriteFileTag (TempHandle); + } else if (OutAppend) { + Status = ShellInfoObject.NewEfiShellProtocol->GetFileSize(TempHandle, &FileSize); + if (!EFI_ERROR(Status)) { + // + // When appending to a new unicode file, write the file tag. + // Otherwise (ie. when appending to a new ASCII file, or an + // existent file with any encoding), just seek to the end. + // + Status = (FileSize == 0 && OutUnicode) ? + WriteFileTag (TempHandle) : + ShellInfoObject.NewEfiShellProtocol->SetFilePosition ( + TempHandle, + FileSize); + } + } + if (!OutUnicode && !EFI_ERROR(Status)) { + TempHandle = CreateFileInterfaceFile(TempHandle, FALSE); + ASSERT(TempHandle != NULL); + } + if (!EFI_ERROR(Status)) { + ShellParameters->StdOut = TempHandle; + gST->ConOut = CreateSimpleTextOutOnFile(TempHandle, &gST->ConsoleOutHandle, gST->ConOut); + } + } + } + + // + // StdOut to a var + // + if (!EFI_ERROR(Status) && StdOutVarName != NULL) { + if (!OutAppend) { + // + // delete existing variable. + // + SHELL_SET_ENVIRONMENT_VARIABLE_V(StdOutVarName, 0, L""); + } + TempHandle = CreateFileInterfaceEnv(StdOutVarName); + ASSERT(TempHandle != NULL); + ShellParameters->StdOut = TempHandle; + gST->ConOut = CreateSimpleTextOutOnFile(TempHandle, &gST->ConsoleOutHandle, gST->ConOut); + } + + // + // StdErr to a var + // + if (!EFI_ERROR(Status) && StdErrVarName != NULL) { + if (!ErrAppend) { + // + // delete existing variable. + // + SHELL_SET_ENVIRONMENT_VARIABLE_V(StdErrVarName, 0, L""); + } + TempHandle = CreateFileInterfaceEnv(StdErrVarName); + ASSERT(TempHandle != NULL); + ShellParameters->StdErr = TempHandle; + gST->StdErr = CreateSimpleTextOutOnFile(TempHandle, &gST->StandardErrorHandle, gST->StdErr); + } + + // + // StdIn from a var + // + if (!EFI_ERROR(Status) && StdInVarName != NULL) { + TempHandle = CreateFileInterfaceEnv(StdInVarName); + if (TempHandle == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + if (!InUnicode) { + TempHandle = CreateFileInterfaceFile(TempHandle, FALSE); + } + Size = 0; + if (TempHandle == NULL || ((EFI_FILE_PROTOCOL*)TempHandle)->Read(TempHandle, &Size, NULL) != EFI_BUFFER_TOO_SMALL) { + Status = EFI_INVALID_PARAMETER; + } else { + ShellParameters->StdIn = TempHandle; + gST->ConIn = CreateSimpleTextInOnFile(TempHandle, &gST->ConsoleInHandle); + } + } + } + + // + // StdIn from a file + // + if (!EFI_ERROR(Status) && StdInFileName != NULL) { + Status = ShellOpenFileByName( + StdInFileName, + &TempHandle, + EFI_FILE_MODE_READ, + 0); + if (!EFI_ERROR(Status)) { + if (!InUnicode) { + // + // Create the ASCII->Unicode conversion layer + // + TempHandle = CreateFileInterfaceFile(TempHandle, FALSE); + } + ShellParameters->StdIn = TempHandle; + gST->ConIn = CreateSimpleTextInOnFile(TempHandle, &gST->ConsoleInHandle); + } + } + } + } + FreePool(CommandLineCopy); + + CalculateEfiHdrCrc(&gST->Hdr); + + if (gST->ConIn == NULL ||gST->ConOut == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } + + if (Status == EFI_NOT_FOUND) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_REDUNDA_REDIR), ShellInfoObject.HiiHandle); + } else if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_INVALID_REDIR), ShellInfoObject.HiiHandle); + } + + return (Status); +} + +/** + Function will replace the current StdIn and StdOut in the ShellParameters protocol + structure with StdIn and StdOut. The current values are de-allocated. + + @param[in, out] ShellParameters Pointer to parameter structure to modify. + @param[in] OldStdIn Pointer to old StdIn. + @param[in] OldStdOut Pointer to old StdOut. + @param[in] OldStdErr Pointer to old StdErr. + @param[in] SystemTableInfo Pointer to old system table information. +**/ +EFI_STATUS +RestoreStdInStdOutStdErr ( + IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters, + IN SHELL_FILE_HANDLE *OldStdIn, + IN SHELL_FILE_HANDLE *OldStdOut, + IN SHELL_FILE_HANDLE *OldStdErr, + IN SYSTEM_TABLE_INFO *SystemTableInfo + ) +{ + SPLIT_LIST *Split; + + if (ShellParameters == NULL + ||OldStdIn == NULL + ||OldStdOut == NULL + ||OldStdErr == NULL + ||SystemTableInfo == NULL) { + return (EFI_INVALID_PARAMETER); + } + if (!IsListEmpty(&ShellInfoObject.SplitList.Link)) { + Split = (SPLIT_LIST*)GetFirstNode(&ShellInfoObject.SplitList.Link); + } else { + Split = NULL; + } + if (ShellParameters->StdIn != *OldStdIn) { + if ((Split != NULL && Split->SplitStdIn != ShellParameters->StdIn) || Split == NULL) { + gEfiShellProtocol->CloseFile(ShellParameters->StdIn); + } + ShellParameters->StdIn = *OldStdIn; + } + if (ShellParameters->StdOut != *OldStdOut) { + if ((Split != NULL && Split->SplitStdOut != ShellParameters->StdOut) || Split == NULL) { + gEfiShellProtocol->CloseFile(ShellParameters->StdOut); + } + ShellParameters->StdOut = *OldStdOut; + } + if (ShellParameters->StdErr != *OldStdErr) { + gEfiShellProtocol->CloseFile(ShellParameters->StdErr); + ShellParameters->StdErr = *OldStdErr; + } + + if (gST->ConIn != SystemTableInfo->ConIn) { + CloseSimpleTextInOnFile(gST->ConIn); + gST->ConIn = SystemTableInfo->ConIn; + gST->ConsoleInHandle = SystemTableInfo->ConInHandle; + } + if (gST->ConOut != SystemTableInfo->ConOut) { + CloseSimpleTextOutOnFile(gST->ConOut); + gST->ConOut = SystemTableInfo->ConOut; + gST->ConsoleOutHandle = SystemTableInfo->ConOutHandle; + } + if (gST->StdErr != SystemTableInfo->ErrOut) { + CloseSimpleTextOutOnFile(gST->StdErr); + gST->StdErr = SystemTableInfo->ErrOut; + gST->StandardErrorHandle = SystemTableInfo->ErrOutHandle; + } + + CalculateEfiHdrCrc(&gST->Hdr); + + return (EFI_SUCCESS); +} +/** + Function will replace the current Argc and Argv in the ShellParameters protocol + structure by parsing NewCommandLine. The current values are returned to the + user. + + If OldArgv or OldArgc is NULL then that value is not returned. + + @param[in, out] ShellParameters Pointer to parameter structure to modify. + @param[in] NewCommandLine The new command line to parse and use. + @param[in] Type The type of operation. + @param[out] OldArgv Pointer to old list of parameters. + @param[out] OldArgc Pointer to old number of items in Argv list. + + + @retval EFI_SUCCESS Operation was successful, Argv and Argc are valid. + @return EFI_INVALID_PARAMETER Some parameters are invalid. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +UpdateArgcArgv( + IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters, + IN CONST CHAR16 *NewCommandLine, + IN SHELL_OPERATION_TYPES Type, + OUT CHAR16 ***OldArgv OPTIONAL, + OUT UINTN *OldArgc OPTIONAL + ) +{ + BOOLEAN StripParamQuotation; + + ASSERT(ShellParameters != NULL); + StripParamQuotation = TRUE; + + if (OldArgc != NULL) { + *OldArgc = ShellParameters->Argc; + } + if (OldArgc != NULL) { + *OldArgv = ShellParameters->Argv; + } + + if (Type == Script_File_Name) { + StripParamQuotation = FALSE; + } + + return ParseCommandLineToArgs( NewCommandLine, + StripParamQuotation, + &(ShellParameters->Argv), + &(ShellParameters->Argc) + ); +} + +/** + Function will replace the current Argc and Argv in the ShellParameters protocol + structure with Argv and Argc. The current values are de-allocated and the + OldArgv must not be deallocated by the caller. + + @param[in, out] ShellParameters pointer to parameter structure to modify + @param[in] OldArgv pointer to old list of parameters + @param[in] OldArgc pointer to old number of items in Argv list +**/ +VOID +RestoreArgcArgv( + IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters, + IN CHAR16 ***OldArgv, + IN UINTN *OldArgc + ) +{ + UINTN LoopCounter; + ASSERT(ShellParameters != NULL); + ASSERT(OldArgv != NULL); + ASSERT(OldArgc != NULL); + + if (ShellParameters->Argv != NULL) { + for ( LoopCounter = 0 + ; LoopCounter < ShellParameters->Argc + ; LoopCounter++ + ){ + FreePool(ShellParameters->Argv[LoopCounter]); + } + FreePool(ShellParameters->Argv); + } + ShellParameters->Argv = *OldArgv; + *OldArgv = NULL; + ShellParameters->Argc = *OldArgc; + *OldArgc = 0; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellParametersProtocol.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellParametersProtocol.h new file mode 100644 index 00000000..d60acf0f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellParametersProtocol.h @@ -0,0 +1,211 @@ +/** @file + Member functions of EFI_SHELL_PARAMETERS_PROTOCOL and functions for creation, + manipulation, and initialization of EFI_SHELL_PARAMETERS_PROTOCOL. + + Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SHELL_PARAMETERS_PROTOCOL_PROVIDER_HEADER_ +#define _SHELL_PARAMETERS_PROTOCOL_PROVIDER_HEADER_ + +#include "Shell.h" + +typedef enum { + Internal_Command, + Script_File_Name, + Efi_Application, + File_Sys_Change, + Unknown_Invalid +} SHELL_OPERATION_TYPES; + +/** + creates a new EFI_SHELL_PARAMETERS_PROTOCOL instance and populates it and then + installs it on our handle and if there is an existing version of the protocol + that one is cached for removal later. + + @param[in, out] NewShellParameters on a successful return, a pointer to pointer + to the newly installed interface. + @param[in, out] RootShellInstance on a successful return, pointer to boolean. + TRUE if this is the root shell instance. + + @retval EFI_SUCCESS the operation completed successfully. + @return other the operation failed. + @sa ReinstallProtocolInterface + @sa InstallProtocolInterface + @sa ParseCommandLineToArgs +**/ +EFI_STATUS +CreatePopulateInstallShellParametersProtocol ( + IN OUT EFI_SHELL_PARAMETERS_PROTOCOL **NewShellParameters, + IN OUT BOOLEAN *RootShellInstance + ); + +/** + frees all memory used by creation and installation of shell parameters protocol + and if there was an old version installed it will restore that one. + + @param NewShellParameters the interface of EFI_SHELL_PARAMETERS_PROTOCOL that is + being cleaned up. + + @retval EFI_SUCCESS the cleanup was successful + @return other the cleanup failed + @sa ReinstallProtocolInterface + @sa UninstallProtocolInterface +**/ +EFI_STATUS +CleanUpShellParametersProtocol ( + IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *NewShellParameters + ); + +/** + Function will replace the current Argc and Argv in the ShellParameters protocol + structure by parsing NewCommandLine. The current values are returned to the + user. + + @param[in, out] ShellParameters pointer to parameter structure to modify + @param[in] NewCommandLine the new command line to parse and use + @param[in] Type the type of operation. + @param[out] OldArgv pointer to old list of parameters + @param[out] OldArgc pointer to old number of items in Argv list + + @retval EFI_SUCCESS operation was successful, Argv and Argc are valid + @return EFI_INVALID_PARAMETER some parameters are invalid + @retval EFI_OUT_OF_RESOURCES a memory allocation failed. +**/ +EFI_STATUS +UpdateArgcArgv( + IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters, + IN CONST CHAR16 *NewCommandLine, + IN SHELL_OPERATION_TYPES Type, + OUT CHAR16 ***OldArgv, + OUT UINTN *OldArgc + ); + +/** + Function will replace the current Argc and Argv in the ShellParameters protocol + structure with Argv and Argc. The current values are de-allocated and the + OldArgv must not be deallocated by the caller. + + @param[in, out] ShellParameters pointer to parameter structure to modify + @param[in] OldArgv pointer to old list of parameters + @param[in] OldArgc pointer to old number of items in Argv list +**/ +VOID +RestoreArgcArgv( + IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters, + IN CHAR16 ***OldArgv, + IN UINTN *OldArgc + ); + +typedef struct { + EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn; + EFI_HANDLE ConInHandle; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut; + EFI_HANDLE ConOutHandle; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ErrOut; + EFI_HANDLE ErrOutHandle; +} SYSTEM_TABLE_INFO; + +/** + Function will replace the current StdIn and StdOut in the ShellParameters protocol + structure by parsing NewCommandLine. The current values are returned to the + user. + + This will also update the system table. + + @param[in, out] ShellParameters Pointer to parameter structure to modify. + @param[in] NewCommandLine The new command line to parse and use. + @param[out] OldStdIn Pointer to old StdIn. + @param[out] OldStdOut Pointer to old StdOut. + @param[out] OldStdErr Pointer to old StdErr. + @param[out] SystemTableInfo Pointer to old system table information. + + @retval EFI_SUCCESS Operation was successful, Argv and Argc are valid. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +UpdateStdInStdOutStdErr( + IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters, + IN CHAR16 *NewCommandLine, + OUT SHELL_FILE_HANDLE *OldStdIn, + OUT SHELL_FILE_HANDLE *OldStdOut, + OUT SHELL_FILE_HANDLE *OldStdErr, + OUT SYSTEM_TABLE_INFO *SystemTableInfo + ); + +/** + Function will replace the current StdIn and StdOut in the ShellParameters protocol + structure with StdIn and StdOut. The current values are de-allocated. + + @param[in, out] ShellParameters Pointer to parameter structure to modify. + @param[in] OldStdIn Pointer to old StdIn. + @param[in] OldStdOut Pointer to old StdOut. + @param[in] OldStdErr Pointer to old StdErr. + @param[in] SystemTableInfo Pointer to old system table information. +**/ +EFI_STATUS +RestoreStdInStdOutStdErr ( + IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters, + IN SHELL_FILE_HANDLE *OldStdIn, + IN SHELL_FILE_HANDLE *OldStdOut, + IN SHELL_FILE_HANDLE *OldStdErr, + IN SYSTEM_TABLE_INFO *SystemTableInfo + ); + +/** + function to populate Argc and Argv. + + This function parses the CommandLine and divides it into standard C style Argc/Argv + parameters for inclusion in EFI_SHELL_PARAMETERS_PROTOCOL. this supports space + delimited and quote surrounded parameter definition. + + @param[in] CommandLine String of command line to parse + @param[in] StripQuotation if TRUE then strip the quotation marks surrounding + the parameters. + @param[in, out] Argv pointer to array of strings; one for each parameter + @param[in, out] Argc pointer to number of strings in Argv array + + @return EFI_SUCCESS the operation was successful + @return EFI_INVALID_PARAMETER some parameters are invalid + @return EFI_OUT_OF_RESOURCES a memory allocation failed. +**/ +EFI_STATUS +ParseCommandLineToArgs( + IN CONST CHAR16 *CommandLine, + IN BOOLEAN StripQuotation, + IN OUT CHAR16 ***Argv, + IN OUT UINTN *Argc + ); + +/** + return the next parameter from a command line string; + + This function moves the next parameter from Walker into TempParameter and moves + Walker up past that parameter for recursive calling. When the final parameter + is moved *Walker will be set to NULL; + + Temp Parameter must be large enough to hold the parameter before calling this + function. + + @param[in, out] Walker pointer to string of command line. Adjusted to + remaining command line on return + @param[in, out] TempParameter pointer to string of command line item extracted. + @param[in] Length Length of (*TempParameter) in bytes + @param[in] StripQuotation if TRUE then strip the quotation marks surrounding + the parameters. + + @return EFI_INVALID_PARAMETER A required parameter was NULL or pointed to a NULL or empty string. + @return EFI_NOT_FOUND A closing " could not be found on the specified string +**/ +EFI_STATUS +GetNextParameter( + IN OUT CHAR16 **Walker, + IN OUT CHAR16 **TempParameter, + IN CONST UINTN Length, + IN BOOLEAN StripQuotation + ); + +#endif //_SHELL_PARAMETERS_PROTOCOL_PROVIDER_HEADER_ + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellProtocol.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellProtocol.c new file mode 100644 index 00000000..ec6712c3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellProtocol.c @@ -0,0 +1,3848 @@ +/** @file + Member functions of EFI_SHELL_PROTOCOL and functions for creation, + manipulation, and initialization of EFI_SHELL_PROTOCOL. + + (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Shell.h" + +#define INIT_NAME_BUFFER_SIZE 128 + +/** + Close an open file handle. + + This function closes a specified file handle. All "dirty" cached file data is + flushed to the device, and the file is closed. In all cases the handle is + closed. + + @param[in] FileHandle The file handle to close. + + @retval EFI_SUCCESS The file handle was closed successfully. +**/ +EFI_STATUS +EFIAPI +EfiShellClose ( + IN SHELL_FILE_HANDLE FileHandle + ) +{ + ShellFileHandleRemove(FileHandle); + return (FileHandleClose(ConvertShellHandleToEfiFileProtocol(FileHandle))); +} + +/** + Internal worker to determine whether there is a BlockIo somewhere + upon the device path specified. + + @param[in] DevicePath The device path to test. + + @retval TRUE gEfiBlockIoProtocolGuid was installed on a handle with this device path + @retval FALSE gEfiBlockIoProtocolGuid was not found. +**/ +BOOLEAN +InternalShellProtocolIsBlockIoPresent( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy; + EFI_STATUS Status; + EFI_HANDLE Handle; + + Handle = NULL; + + DevicePathCopy = (EFI_DEVICE_PATH_PROTOCOL*)DevicePath; + Status = gBS->LocateDevicePath(&gEfiBlockIoProtocolGuid, &DevicePathCopy, &Handle); + + if ((Handle != NULL) && (!EFI_ERROR(Status))) { + return (TRUE); + } + return (FALSE); +} + +/** + Internal worker to determine whether there is a file system somewhere + upon the device path specified. + + @param[in] DevicePath The device path to test. + + @retval TRUE gEfiSimpleFileSystemProtocolGuid was installed on a handle with this device path + @retval FALSE gEfiSimpleFileSystemProtocolGuid was not found. +**/ +BOOLEAN +InternalShellProtocolIsSimpleFileSystemPresent( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy; + EFI_STATUS Status; + EFI_HANDLE Handle; + + Handle = NULL; + + DevicePathCopy = (EFI_DEVICE_PATH_PROTOCOL*)DevicePath; + Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &Handle); + + if ((Handle != NULL) && (!EFI_ERROR(Status))) { + return (TRUE); + } + return (FALSE); +} + + +/** + This function creates a mapping for a device path. + + If both DevicePath and Mapping are NULL, this will reset the mapping to default values. + + @param DevicePath Points to the device path. If this is NULL and Mapping points to a valid mapping, + then the mapping will be deleted. + @param Mapping Points to the NULL-terminated mapping for the device path. Must end with a ':' + + @retval EFI_SUCCESS Mapping created or deleted successfully. + @retval EFI_NO_MAPPING There is no handle that corresponds exactly to DevicePath. See the + boot service function LocateDevicePath(). + @retval EFI_ACCESS_DENIED The mapping is a built-in alias. + @retval EFI_INVALID_PARAMETER Mapping was NULL + @retval EFI_INVALID_PARAMETER Mapping did not end with a ':' + @retval EFI_INVALID_PARAMETER DevicePath was not pointing at a device that had a SIMPLE_FILE_SYSTEM_PROTOCOL installed. + @retval EFI_NOT_FOUND There was no mapping found to delete + @retval EFI_OUT_OF_RESOURCES Memory allocation failed +**/ +EFI_STATUS +EFIAPI +EfiShellSetMap( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL, + IN CONST CHAR16 *Mapping + ) +{ + EFI_STATUS Status; + SHELL_MAP_LIST *MapListNode; + + if (Mapping == NULL){ + return (EFI_INVALID_PARAMETER); + } + + if (Mapping[StrLen(Mapping)-1] != ':') { + return (EFI_INVALID_PARAMETER); + } + + // + // Delete the mapping + // + if (DevicePath == NULL) { + if (IsListEmpty(&gShellMapList.Link)) { + return (EFI_NOT_FOUND); + } + for ( MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link) + ; !IsNull(&gShellMapList.Link, &MapListNode->Link) + ; MapListNode = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &MapListNode->Link) + ){ + if (StringNoCaseCompare(&MapListNode->MapName, &Mapping) == 0) { + RemoveEntryList(&MapListNode->Link); + SHELL_FREE_NON_NULL(MapListNode->DevicePath); + SHELL_FREE_NON_NULL(MapListNode->MapName); + SHELL_FREE_NON_NULL(MapListNode->CurrentDirectoryPath); + FreePool(MapListNode); + return (EFI_SUCCESS); + } + } // for loop + + // + // We didn't find one to delete + // + return (EFI_NOT_FOUND); + } + + // + // make sure this is a valid to add device path + // + ///@todo add BlockIo to this test... + if (!InternalShellProtocolIsSimpleFileSystemPresent(DevicePath) + && !InternalShellProtocolIsBlockIoPresent(DevicePath)) { + return (EFI_INVALID_PARAMETER); + } + + // + // First make sure there is no old mapping + // + Status = EfiShellSetMap(NULL, Mapping); + if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_FOUND)) { + return (Status); + } + + // + // now add the new one. + // + Status = ShellCommandAddMapItemAndUpdatePath(Mapping, DevicePath, 0, FALSE); + + return(Status); +} + +/** + Gets the device path from the mapping. + + This function gets the device path associated with a mapping. + + @param Mapping A pointer to the mapping + + @retval !=NULL Pointer to the device path that corresponds to the + device mapping. The returned pointer does not need + to be freed. + @retval NULL There is no device path associated with the + specified mapping. +**/ +CONST EFI_DEVICE_PATH_PROTOCOL * +EFIAPI +EfiShellGetDevicePathFromMap( + IN CONST CHAR16 *Mapping + ) +{ + SHELL_MAP_LIST *MapListItem; + CHAR16 *NewName; + UINTN Size; + + NewName = NULL; + Size = 0; + + StrnCatGrow(&NewName, &Size, Mapping, 0); + if (Mapping[StrLen(Mapping)-1] != L':') { + StrnCatGrow(&NewName, &Size, L":", 0); + } + + MapListItem = ShellCommandFindMapItem(NewName); + + FreePool(NewName); + + if (MapListItem != NULL) { + return (MapListItem->DevicePath); + } + return(NULL); +} + +/** + Gets the mapping(s) that most closely matches the device path. + + This function gets the mapping which corresponds to the device path *DevicePath. If + there is no exact match, then the mapping which most closely matches *DevicePath + is returned, and *DevicePath is updated to point to the remaining portion of the + device path. If there is an exact match, the mapping is returned and *DevicePath + points to the end-of-device-path node. + + If there are multiple map names they will be semi-colon separated in the + NULL-terminated string. + + @param DevicePath On entry, points to a device path pointer. On + exit, updates the pointer to point to the + portion of the device path after the mapping. + + @retval NULL No mapping was found. + @return !=NULL Pointer to NULL-terminated mapping. The buffer + is callee allocated and should be freed by the caller. +**/ +CONST CHAR16 * +EFIAPI +EfiShellGetMapFromDevicePath( + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath + ) +{ + SHELL_MAP_LIST *Node; + CHAR16 *PathForReturn; + UINTN PathSize; +// EFI_HANDLE PathHandle; +// EFI_HANDLE MapHandle; +// EFI_STATUS Status; +// EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy; +// EFI_DEVICE_PATH_PROTOCOL *MapPathCopy; + + if (DevicePath == NULL || *DevicePath == NULL) { + return (NULL); + } + + PathForReturn = NULL; + PathSize = 0; + + for ( Node = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link) + ; !IsNull(&gShellMapList.Link, &Node->Link) + ; Node = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &Node->Link) + ){ + // + // check for exact match + // + if (DevicePathCompare(DevicePath, &Node->DevicePath) == 0) { + ASSERT((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL)); + if (PathSize != 0) { + PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L";", 0); + } + PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, Node->MapName, 0); + } + } + if (PathForReturn != NULL) { + while (!IsDevicePathEndType (*DevicePath)) { + *DevicePath = NextDevicePathNode (*DevicePath); + } + SetDevicePathEndNode (*DevicePath); + } +/* + ///@todo finish code for inexact matches. + if (PathForReturn == NULL) { + PathSize = 0; + + DevicePathCopy = DuplicateDevicePath(*DevicePath); + ASSERT(DevicePathCopy != NULL); + Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &PathHandle); + ASSERT_EFI_ERROR(Status); + // + // check each of the device paths we have to get the root of the path for consist mappings + // + for ( Node = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link) + ; !IsNull(&gShellMapList.Link, &Node->Link) + ; Node = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &Node->Link) + ){ + if ((Node->Flags & SHELL_MAP_FLAGS_CONSIST) == 0) { + continue; + } + MapPathCopy = DuplicateDevicePath(Node->DevicePath); + ASSERT(MapPathCopy != NULL); + Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle); + if (MapHandle == PathHandle) { + + *DevicePath = DevicePathCopy; + + MapPathCopy = NULL; + DevicePathCopy = NULL; + PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, Node->MapName, 0); + PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L";", 0); + break; + } + } + // + // now add on the non-consistent mappings + // + for ( Node = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link) + ; !IsNull(&gShellMapList.Link, &Node->Link) + ; Node = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &Node->Link) + ){ + if ((Node->Flags & SHELL_MAP_FLAGS_CONSIST) != 0) { + continue; + } + MapPathCopy = Node->DevicePath; + ASSERT(MapPathCopy != NULL); + Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle); + if (MapHandle == PathHandle) { + PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, Node->MapName, 0); + PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L";", 0); + break; + } + } + } +*/ + + return (AddBufferToFreeList(PathForReturn)); +} + +/** + Converts a device path to a file system-style path. + + This function converts a device path to a file system path by replacing part, or all, of + the device path with the file-system mapping. If there are more than one application + file system mappings, the one that most closely matches Path will be used. + + @param Path The pointer to the device path + + @retval NULL the device path could not be found. + @return all The pointer of the NULL-terminated file path. The path + is callee-allocated and should be freed by the caller. +**/ +CHAR16 * +EFIAPI +EfiShellGetFilePathFromDevicePath( + IN CONST EFI_DEVICE_PATH_PROTOCOL *Path + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy; + EFI_DEVICE_PATH_PROTOCOL *MapPathCopy; + SHELL_MAP_LIST *MapListItem; + CHAR16 *PathForReturn; + UINTN PathSize; + EFI_HANDLE PathHandle; + EFI_HANDLE MapHandle; + EFI_STATUS Status; + FILEPATH_DEVICE_PATH *FilePath; + FILEPATH_DEVICE_PATH *AlignedNode; + + PathForReturn = NULL; + PathSize = 0; + + DevicePathCopy = (EFI_DEVICE_PATH_PROTOCOL*)Path; + ASSERT(DevicePathCopy != NULL); + if (DevicePathCopy == NULL) { + return (NULL); + } + ///@todo BlockIo? + Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &PathHandle); + + if (EFI_ERROR(Status)) { + return (NULL); + } + // + // check each of the device paths we have to get the root of the path + // + for ( MapListItem = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link) + ; !IsNull(&gShellMapList.Link, &MapListItem->Link) + ; MapListItem = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &MapListItem->Link) + ){ + MapPathCopy = (EFI_DEVICE_PATH_PROTOCOL*)MapListItem->DevicePath; + ASSERT(MapPathCopy != NULL); + ///@todo BlockIo? + Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle); + if (MapHandle == PathHandle) { + ASSERT((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL)); + PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, MapListItem->MapName, 0); + // + // go through all the remaining nodes in the device path + // + for ( FilePath = (FILEPATH_DEVICE_PATH*)DevicePathCopy + ; !IsDevicePathEnd (&FilePath->Header) + ; FilePath = (FILEPATH_DEVICE_PATH*)NextDevicePathNode (&FilePath->Header) + ){ + // + // If any node is not a file path node, then the conversion can not be completed + // + if ((DevicePathType(&FilePath->Header) != MEDIA_DEVICE_PATH) || + (DevicePathSubType(&FilePath->Header) != MEDIA_FILEPATH_DP)) { + FreePool(PathForReturn); + return NULL; + } + + // + // append the path part onto the filepath. + // + ASSERT((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL)); + + AlignedNode = AllocateCopyPool (DevicePathNodeLength(FilePath), FilePath); + if (AlignedNode == NULL) { + FreePool (PathForReturn); + return NULL; + } + + // File Path Device Path Nodes 'can optionally add a "\" separator to + // the beginning and/or the end of the Path Name string.' + // (UEFI Spec 2.4 section 9.3.6.4). + // If necessary, add a "\", but otherwise don't + // (This is specified in the above section, and also implied by the + // UEFI Shell spec section 3.7) + if ((PathSize != 0) && + (PathForReturn != NULL) && + (PathForReturn[PathSize / sizeof (CHAR16) - 1] != L'\\') && + (AlignedNode->PathName[0] != L'\\')) { + PathForReturn = StrnCatGrow (&PathForReturn, &PathSize, L"\\", 1); + } + + PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, AlignedNode->PathName, 0); + FreePool(AlignedNode); + } // for loop of remaining nodes + } + if (PathForReturn != NULL) { + break; + } + } // for loop of paths to check + return(PathForReturn); +} + +/** + Converts a file system style name to a device path. + + This function converts a file system style name to a device path, by replacing any + mapping references to the associated device path. + + @param[in] Path The pointer to the path. + + @return The pointer of the file path. The file path is callee + allocated and should be freed by the caller. + @retval NULL The path could not be found. + @retval NULL There was not enough available memory. +**/ +EFI_DEVICE_PATH_PROTOCOL * +EFIAPI +EfiShellGetDevicePathFromFilePath( + IN CONST CHAR16 *Path + ) +{ + CHAR16 *MapName; + CHAR16 *NewPath; + CONST CHAR16 *Cwd; + UINTN Size; + CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy; + EFI_DEVICE_PATH_PROTOCOL *DevicePathCopyForFree; + EFI_DEVICE_PATH_PROTOCOL *DevicePathForReturn; + EFI_HANDLE Handle; + EFI_STATUS Status; + + if (Path == NULL) { + return (NULL); + } + + MapName = NULL; + NewPath = NULL; + + if (StrStr(Path, L":") == NULL) { + Cwd = EfiShellGetCurDir(NULL); + if (Cwd == NULL) { + return (NULL); + } + Size = StrSize(Cwd) + StrSize(Path); + NewPath = AllocateZeroPool(Size); + if (NewPath == NULL) { + return (NULL); + } + StrCpyS(NewPath, Size/sizeof(CHAR16), Cwd); + StrCatS(NewPath, Size/sizeof(CHAR16), L"\\"); + if (*Path == L'\\') { + Path++; + while (PathRemoveLastItem(NewPath)) ; + } + StrCatS(NewPath, Size/sizeof(CHAR16), Path); + DevicePathForReturn = EfiShellGetDevicePathFromFilePath(NewPath); + FreePool(NewPath); + return (DevicePathForReturn); + } + + Size = 0; + // + // find the part before (but including) the : for the map name + // + ASSERT((MapName == NULL && Size == 0) || (MapName != NULL)); + MapName = StrnCatGrow(&MapName, &Size, Path, (StrStr(Path, L":")-Path+1)); + if (MapName == NULL || MapName[StrLen(MapName)-1] != L':') { + return (NULL); + } + + // + // look up the device path in the map + // + DevicePath = EfiShellGetDevicePathFromMap(MapName); + if (DevicePath == NULL) { + // + // Must have been a bad Mapname + // + return (NULL); + } + + // + // make a copy for LocateDevicePath to modify (also save a pointer to call FreePool with) + // + DevicePathCopyForFree = DevicePathCopy = DuplicateDevicePath(DevicePath); + if (DevicePathCopy == NULL) { + FreePool(MapName); + return (NULL); + } + + // + // get the handle + // + ///@todo BlockIo? + Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &Handle); + if (EFI_ERROR(Status)) { + if (DevicePathCopyForFree != NULL) { + FreePool(DevicePathCopyForFree); + } + FreePool(MapName); + return (NULL); + } + + // + // build the full device path + // + if ((*(Path+StrLen(MapName)) != CHAR_NULL) && + (*(Path+StrLen(MapName)+1) == CHAR_NULL)) { + DevicePathForReturn = FileDevicePath(Handle, L"\\"); + } else { + DevicePathForReturn = FileDevicePath(Handle, Path+StrLen(MapName)); + } + + FreePool(MapName); + if (DevicePathCopyForFree != NULL) { + FreePool(DevicePathCopyForFree); + } + + return (DevicePathForReturn); +} + +/** + Gets the name of the device specified by the device handle. + + This function gets the user-readable name of the device specified by the device + handle. If no user-readable name could be generated, then *BestDeviceName will be + NULL and EFI_NOT_FOUND will be returned. + + If EFI_DEVICE_NAME_USE_COMPONENT_NAME is set, then the function will return the + device's name using the EFI_COMPONENT_NAME2_PROTOCOL, if present on + DeviceHandle. + + If EFI_DEVICE_NAME_USE_DEVICE_PATH is set, then the function will return the + device's name using the EFI_DEVICE_PATH_PROTOCOL, if present on DeviceHandle. + If both EFI_DEVICE_NAME_USE_COMPONENT_NAME and + EFI_DEVICE_NAME_USE_DEVICE_PATH are set, then + EFI_DEVICE_NAME_USE_COMPONENT_NAME will have higher priority. + + @param DeviceHandle The handle of the device. + @param Flags Determines the possible sources of component names. + Valid bits are: + EFI_DEVICE_NAME_USE_COMPONENT_NAME + EFI_DEVICE_NAME_USE_DEVICE_PATH + @param Language A pointer to the language specified for the device + name, in the same format as described in the UEFI + specification, Appendix M + @param BestDeviceName On return, points to the callee-allocated NULL- + terminated name of the device. If no device name + could be found, points to NULL. The name must be + freed by the caller... + + @retval EFI_SUCCESS Get the name successfully. + @retval EFI_NOT_FOUND Fail to get the device name. + @retval EFI_INVALID_PARAMETER Flags did not have a valid bit set. + @retval EFI_INVALID_PARAMETER BestDeviceName was NULL + @retval EFI_INVALID_PARAMETER DeviceHandle was NULL +**/ +EFI_STATUS +EFIAPI +EfiShellGetDeviceName( + IN EFI_HANDLE DeviceHandle, + IN EFI_SHELL_DEVICE_NAME_FLAGS Flags, + IN CHAR8 *Language, + OUT CHAR16 **BestDeviceName + ) +{ + EFI_STATUS Status; + EFI_COMPONENT_NAME2_PROTOCOL *CompName2; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_HANDLE *HandleList; + UINTN HandleCount; + UINTN LoopVar; + CHAR16 *DeviceNameToReturn; + CHAR8 *Lang; + UINTN ParentControllerCount; + EFI_HANDLE *ParentControllerBuffer; + UINTN ParentDriverCount; + EFI_HANDLE *ParentDriverBuffer; + + if (BestDeviceName == NULL || + DeviceHandle == NULL + ){ + return (EFI_INVALID_PARAMETER); + } + + // + // make sure one of the 2 supported bits is on + // + if (((Flags & EFI_DEVICE_NAME_USE_COMPONENT_NAME) == 0) && + ((Flags & EFI_DEVICE_NAME_USE_DEVICE_PATH) == 0)) { + return (EFI_INVALID_PARAMETER); + } + + DeviceNameToReturn = NULL; + *BestDeviceName = NULL; + HandleList = NULL; + HandleCount = 0; + Lang = NULL; + + if ((Flags & EFI_DEVICE_NAME_USE_COMPONENT_NAME) != 0) { + Status = ParseHandleDatabaseByRelationship( + NULL, + DeviceHandle, + HR_DRIVER_BINDING_HANDLE|HR_DEVICE_DRIVER, + &HandleCount, + &HandleList); + for (LoopVar = 0; LoopVar < HandleCount ; LoopVar++){ + // + // Go through those handles until we get one that passes for GetComponentName + // + Status = gBS->OpenProtocol( + HandleList[LoopVar], + &gEfiComponentName2ProtocolGuid, + (VOID**)&CompName2, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(Status)) { + Status = gBS->OpenProtocol( + HandleList[LoopVar], + &gEfiComponentNameProtocolGuid, + (VOID**)&CompName2, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + } + + if (EFI_ERROR(Status)) { + continue; + } + Lang = GetBestLanguageForDriver(CompName2->SupportedLanguages, Language, FALSE); + Status = CompName2->GetControllerName(CompName2, DeviceHandle, NULL, Lang, &DeviceNameToReturn); + FreePool(Lang); + Lang = NULL; + if (!EFI_ERROR(Status) && DeviceNameToReturn != NULL) { + break; + } + } + if (HandleList != NULL) { + FreePool(HandleList); + } + + // + // Now check the parent controller using this as the child. + // + if (DeviceNameToReturn == NULL){ + PARSE_HANDLE_DATABASE_PARENTS(DeviceHandle, &ParentControllerCount, &ParentControllerBuffer); + for (LoopVar = 0 ; LoopVar < ParentControllerCount ; LoopVar++) { + PARSE_HANDLE_DATABASE_UEFI_DRIVERS(ParentControllerBuffer[LoopVar], &ParentDriverCount, &ParentDriverBuffer); + for (HandleCount = 0 ; HandleCount < ParentDriverCount ; HandleCount++) { + // + // try using that driver's component name with controller and our driver as the child. + // + Status = gBS->OpenProtocol( + ParentDriverBuffer[HandleCount], + &gEfiComponentName2ProtocolGuid, + (VOID**)&CompName2, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(Status)) { + Status = gBS->OpenProtocol( + ParentDriverBuffer[HandleCount], + &gEfiComponentNameProtocolGuid, + (VOID**)&CompName2, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + } + + if (EFI_ERROR(Status)) { + continue; + } + Lang = GetBestLanguageForDriver(CompName2->SupportedLanguages, Language, FALSE); + Status = CompName2->GetControllerName(CompName2, ParentControllerBuffer[LoopVar], DeviceHandle, Lang, &DeviceNameToReturn); + FreePool(Lang); + Lang = NULL; + if (!EFI_ERROR(Status) && DeviceNameToReturn != NULL) { + break; + } + + + + } + SHELL_FREE_NON_NULL(ParentDriverBuffer); + if (!EFI_ERROR(Status) && DeviceNameToReturn != NULL) { + break; + } + } + SHELL_FREE_NON_NULL(ParentControllerBuffer); + } + // + // dont return on fail since we will try device path if that bit is on + // + if (DeviceNameToReturn != NULL){ + ASSERT(BestDeviceName != NULL); + StrnCatGrow(BestDeviceName, NULL, DeviceNameToReturn, 0); + return (EFI_SUCCESS); + } + } + if ((Flags & EFI_DEVICE_NAME_USE_DEVICE_PATH) != 0) { + Status = gBS->OpenProtocol( + DeviceHandle, + &gEfiDevicePathProtocolGuid, + (VOID**)&DevicePath, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (!EFI_ERROR(Status)) { + // + // use device path to text on the device path + // + *BestDeviceName = ConvertDevicePathToText(DevicePath, TRUE, TRUE); + return (EFI_SUCCESS); + } + } + // + // none of the selected bits worked. + // + return (EFI_NOT_FOUND); +} + +/** + Opens the root directory of a device on a handle + + This function opens the root directory of a device and returns a file handle to it. + + @param DeviceHandle The handle of the device that contains the volume. + @param FileHandle On exit, points to the file handle corresponding to the root directory on the + device. + + @retval EFI_SUCCESS Root opened successfully. + @retval EFI_NOT_FOUND EFI_SIMPLE_FILE_SYSTEM could not be found or the root directory + could not be opened. + @retval EFI_VOLUME_CORRUPTED The data structures in the volume were corrupted. + @retval EFI_DEVICE_ERROR The device had an error. + @retval Others Error status returned from EFI_SIMPLE_FILE_SYSTEM_PROTOCOL->OpenVolume(). +**/ +EFI_STATUS +EFIAPI +EfiShellOpenRootByHandle( + IN EFI_HANDLE DeviceHandle, + OUT SHELL_FILE_HANDLE *FileHandle + ) +{ + EFI_STATUS Status; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem; + EFI_FILE_PROTOCOL *RealFileHandle; + EFI_DEVICE_PATH_PROTOCOL *DevPath; + + // + // get the simple file system interface + // + Status = gBS->OpenProtocol(DeviceHandle, + &gEfiSimpleFileSystemProtocolGuid, + (VOID**)&SimpleFileSystem, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(Status)) { + return (EFI_NOT_FOUND); + } + + Status = gBS->OpenProtocol(DeviceHandle, + &gEfiDevicePathProtocolGuid, + (VOID**)&DevPath, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(Status)) { + return (EFI_NOT_FOUND); + } + // + // Open the root volume now... + // + Status = SimpleFileSystem->OpenVolume(SimpleFileSystem, &RealFileHandle); + if (EFI_ERROR(Status)) { + return Status; + } + + *FileHandle = ConvertEfiFileProtocolToShellHandle(RealFileHandle, EfiShellGetMapFromDevicePath(&DevPath)); + return (EFI_SUCCESS); +} + +/** + Opens the root directory of a device. + + This function opens the root directory of a device and returns a file handle to it. + + @param DevicePath Points to the device path corresponding to the device where the + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL is installed. + @param FileHandle On exit, points to the file handle corresponding to the root directory on the + device. + + @retval EFI_SUCCESS Root opened successfully. + @retval EFI_NOT_FOUND EFI_SIMPLE_FILE_SYSTEM could not be found or the root directory + could not be opened. + @retval EFI_VOLUME_CORRUPTED The data structures in the volume were corrupted. + @retval EFI_DEVICE_ERROR The device had an error + @retval EFI_INVALID_PARAMETER FileHandle is NULL. +**/ +EFI_STATUS +EFIAPI +EfiShellOpenRoot( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT SHELL_FILE_HANDLE *FileHandle + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + if (FileHandle == NULL) { + return (EFI_INVALID_PARAMETER); + } + + // + // find the handle of the device with that device handle and the file system + // + ///@todo BlockIo? + Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, + &DevicePath, + &Handle); + if (EFI_ERROR(Status)) { + return (EFI_NOT_FOUND); + } + + return (EfiShellOpenRootByHandle(Handle, FileHandle)); +} + +/** + Returns whether any script files are currently being processed. + + @retval TRUE There is at least one script file active. + @retval FALSE No script files are active now. + +**/ +BOOLEAN +EFIAPI +EfiShellBatchIsActive ( + VOID + ) +{ + if (ShellCommandGetCurrentScriptFile() == NULL) { + return (FALSE); + } + return (TRUE); +} + +/** + Worker function to open a file based on a device path. this will open the root + of the volume and then traverse down to the file itself. + + @param DevicePath Device Path of the file. + @param FileHandle Pointer to the file upon a successful return. + @param OpenMode mode to open file in. + @param Attributes the File Attributes to use when creating a new file. + + @retval EFI_SUCCESS the file is open and FileHandle is valid + @retval EFI_UNSUPPORTED the device path contained non-path elements + @retval other an error occurred. +**/ +EFI_STATUS +InternalOpenFileDevicePath( + IN OUT EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT SHELL_FILE_HANDLE *FileHandle, + IN UINT64 OpenMode, + IN UINT64 Attributes OPTIONAL + ) +{ + EFI_STATUS Status; + FILEPATH_DEVICE_PATH *FilePathNode; + EFI_HANDLE Handle; + SHELL_FILE_HANDLE ShellHandle; + EFI_FILE_PROTOCOL *Handle1; + EFI_FILE_PROTOCOL *Handle2; + FILEPATH_DEVICE_PATH *AlignedNode; + + if (FileHandle == NULL) { + return (EFI_INVALID_PARAMETER); + } + *FileHandle = NULL; + Handle1 = NULL; + Handle2 = NULL; + Handle = NULL; + ShellHandle = NULL; + FilePathNode = NULL; + AlignedNode = NULL; + + Status = EfiShellOpenRoot(DevicePath, &ShellHandle); + + if (!EFI_ERROR(Status)) { + Handle1 = ConvertShellHandleToEfiFileProtocol(ShellHandle); + if (Handle1 != NULL) { + // + // chop off the beginning part before the file system part... + // + ///@todo BlockIo? + Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, + &DevicePath, + &Handle); + if (!EFI_ERROR(Status)) { + // + // To access as a file system, the file path should only + // contain file path components. Follow the file path nodes + // and find the target file + // + for ( FilePathNode = (FILEPATH_DEVICE_PATH *)DevicePath + ; !IsDevicePathEnd (&FilePathNode->Header) + ; FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode (&FilePathNode->Header) + ){ + SHELL_FREE_NON_NULL(AlignedNode); + AlignedNode = AllocateCopyPool (DevicePathNodeLength(FilePathNode), FilePathNode); + // + // For file system access each node should be a file path component + // + if (DevicePathType (&FilePathNode->Header) != MEDIA_DEVICE_PATH || + DevicePathSubType (&FilePathNode->Header) != MEDIA_FILEPATH_DP + ) { + Status = EFI_UNSUPPORTED; + break; + } + + // + // Open this file path node + // + Handle2 = Handle1; + Handle1 = NULL; + + // + // if this is the last node in the DevicePath always create (if that was requested). + // + if (IsDevicePathEnd ((NextDevicePathNode (&FilePathNode->Header)))) { + Status = Handle2->Open ( + Handle2, + &Handle1, + AlignedNode->PathName, + OpenMode, + Attributes + ); + } else { + + // + // This is not the last node and we dont want to 'create' existing + // directory entries... + // + + // + // open without letting it create + // prevents error on existing files/directories + // + Status = Handle2->Open ( + Handle2, + &Handle1, + AlignedNode->PathName, + OpenMode &~EFI_FILE_MODE_CREATE, + Attributes + ); + // + // if above failed now open and create the 'item' + // if OpenMode EFI_FILE_MODE_CREATE bit was on (but disabled above) + // + if ((EFI_ERROR (Status)) && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)) { + Status = Handle2->Open ( + Handle2, + &Handle1, + AlignedNode->PathName, + OpenMode, + Attributes + ); + } + } + // + // Close the last node + // + ShellInfoObject.NewEfiShellProtocol->CloseFile (Handle2); + + // + // If there's been an error, stop + // + if (EFI_ERROR (Status)) { + break; + } + } // for loop + } + } + } + SHELL_FREE_NON_NULL(AlignedNode); + if (EFI_ERROR(Status)) { + if (Handle1 != NULL) { + ShellInfoObject.NewEfiShellProtocol->CloseFile(Handle1); + } + } else { + *FileHandle = ConvertEfiFileProtocolToShellHandle(Handle1, ShellFileHandleGetPath(ShellHandle)); + } + return (Status); +} + +/** + Creates a file or directory by name. + + This function creates an empty new file or directory with the specified attributes and + returns the new file's handle. If the file already exists and is read-only, then + EFI_INVALID_PARAMETER will be returned. + + If the file already existed, it is truncated and its attributes updated. If the file is + created successfully, the FileHandle is the file's handle, else, the FileHandle is NULL. + + If the file name begins with >v, then the file handle which is returned refers to the + shell environment variable with the specified name. If the shell environment variable + already exists and is non-volatile then EFI_INVALID_PARAMETER is returned. + + @param FileName Pointer to NULL-terminated file path + @param FileAttribs The new file's attributes. the different attributes are + described in EFI_FILE_PROTOCOL.Open(). + @param FileHandle On return, points to the created file handle or directory's handle + + @retval EFI_SUCCESS The file was opened. FileHandle points to the new file's handle. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + @retval EFI_UNSUPPORTED could not open the file path + @retval EFI_NOT_FOUND the specified file could not be found on the device, or could not + file the file system on the device. + @retval EFI_NO_MEDIA the device has no medium. + @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no + longer supported. + @retval EFI_DEVICE_ERROR The device reported an error or can't get the file path according + the DirName. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write + when the media is write-protected. + @retval EFI_ACCESS_DENIED The service denied access to the file. + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. + @retval EFI_VOLUME_FULL The volume is full. +**/ +EFI_STATUS +EFIAPI +EfiShellCreateFile( + IN CONST CHAR16 *FileName, + IN UINT64 FileAttribs, + OUT SHELL_FILE_HANDLE *FileHandle + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_STATUS Status; + BOOLEAN Volatile; + + // + // Is this for an environment variable + // do we start with >v + // + if (StrStr(FileName, L">v") == FileName) { + Status = IsVolatileEnv (FileName + 2, &Volatile); + if (EFI_ERROR (Status)) { + return Status; + } + if (!Volatile) { + return (EFI_INVALID_PARAMETER); + } + *FileHandle = CreateFileInterfaceEnv(FileName+2); + return (EFI_SUCCESS); + } + + // + // We are opening a regular file. + // + DevicePath = EfiShellGetDevicePathFromFilePath(FileName); + if (DevicePath == NULL) { + return (EFI_NOT_FOUND); + } + + Status = InternalOpenFileDevicePath(DevicePath, FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, FileAttribs); + FreePool(DevicePath); + + return(Status); +} + +/** + Register a GUID and a localized human readable name for it. + + If Guid is not assigned a name, then assign GuidName to Guid. This list of GUID + names must be used whenever a shell command outputs GUID information. + + This function is only available when the major and minor versions in the + EfiShellProtocol are greater than or equal to 2 and 1, respectively. + + @param[in] Guid A pointer to the GUID being registered. + @param[in] GuidName A pointer to the localized name for the GUID being registered. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_INVALID_PARAMETER Guid was NULL. + @retval EFI_INVALID_PARAMETER GuidName was NULL. + @retval EFI_ACCESS_DENIED Guid already is assigned a name. +**/ +EFI_STATUS +EFIAPI +EfiShellRegisterGuidName( + IN CONST EFI_GUID *Guid, + IN CONST CHAR16 *GuidName + ) +{ + return (AddNewGuidNameMapping(Guid, GuidName, NULL)); +} + +/** + Opens a file or a directory by file name. + + This function opens the specified file in the specified OpenMode and returns a file + handle. + If the file name begins with >v, then the file handle which is returned refers to the + shell environment variable with the specified name. If the shell environment variable + exists, is non-volatile and the OpenMode indicates EFI_FILE_MODE_WRITE, then + EFI_INVALID_PARAMETER is returned. + + If the file name is >i, then the file handle which is returned refers to the standard + input. If the OpenMode indicates EFI_FILE_MODE_WRITE, then EFI_INVALID_PARAMETER + is returned. + + If the file name is >o, then the file handle which is returned refers to the standard + output. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER + is returned. + + If the file name is >e, then the file handle which is returned refers to the standard + error. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER + is returned. + + If the file name is NUL, then the file handle that is returned refers to the standard NUL + file. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER is + returned. + + If return EFI_SUCCESS, the FileHandle is the opened file's handle, else, the + FileHandle is NULL. + + @param FileName Points to the NULL-terminated UCS-2 encoded file name. + @param FileHandle On return, points to the file handle. + @param OpenMode File open mode. Either EFI_FILE_MODE_READ or + EFI_FILE_MODE_WRITE from section 12.4 of the UEFI + Specification. + @retval EFI_SUCCESS The file was opened. FileHandle has the opened file's handle. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. FileHandle is NULL. + @retval EFI_UNSUPPORTED Could not open the file path. FileHandle is NULL. + @retval EFI_NOT_FOUND The specified file could not be found on the device or the file + system could not be found on the device. FileHandle is NULL. + @retval EFI_NO_MEDIA The device has no medium. FileHandle is NULL. + @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no + longer supported. FileHandle is NULL. + @retval EFI_DEVICE_ERROR The device reported an error or can't get the file path according + the FileName. FileHandle is NULL. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. FileHandle is NULL. + @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write + when the media is write-protected. FileHandle is NULL. + @retval EFI_ACCESS_DENIED The service denied access to the file. FileHandle is NULL. + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. FileHandle + is NULL. + @retval EFI_VOLUME_FULL The volume is full. FileHandle is NULL. +**/ +EFI_STATUS +EFIAPI +EfiShellOpenFileByName( + IN CONST CHAR16 *FileName, + OUT SHELL_FILE_HANDLE *FileHandle, + IN UINT64 OpenMode + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_STATUS Status; + BOOLEAN Volatile; + + *FileHandle = NULL; + + // + // Is this for StdIn + // + if (StrCmp(FileName, L">i") == 0) { + // + // make sure not writing to StdIn + // + if ((OpenMode & EFI_FILE_MODE_WRITE) != 0) { + return (EFI_INVALID_PARAMETER); + } + *FileHandle = ShellInfoObject.NewShellParametersProtocol->StdIn; + ASSERT(*FileHandle != NULL); + return (EFI_SUCCESS); + } + + // + // Is this for StdOut + // + if (StrCmp(FileName, L">o") == 0) { + // + // make sure not writing to StdIn + // + if ((OpenMode & EFI_FILE_MODE_READ) != 0) { + return (EFI_INVALID_PARAMETER); + } + *FileHandle = &FileInterfaceStdOut; + return (EFI_SUCCESS); + } + + // + // Is this for NUL / NULL file + // + if ((gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16*)FileName, L"NUL") == 0) || + (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16*)FileName, L"NULL") == 0)) { + *FileHandle = &FileInterfaceNulFile; + return (EFI_SUCCESS); + } + + // + // Is this for StdErr + // + if (StrCmp(FileName, L">e") == 0) { + // + // make sure not writing to StdIn + // + if ((OpenMode & EFI_FILE_MODE_READ) != 0) { + return (EFI_INVALID_PARAMETER); + } + *FileHandle = &FileInterfaceStdErr; + return (EFI_SUCCESS); + } + + // + // Is this for an environment variable + // do we start with >v + // + if (StrStr(FileName, L">v") == FileName) { + Status = IsVolatileEnv (FileName + 2, &Volatile); + if (EFI_ERROR (Status)) { + return Status; + } + if (!Volatile && + ((OpenMode & EFI_FILE_MODE_WRITE) != 0)) { + return (EFI_INVALID_PARAMETER); + } + *FileHandle = CreateFileInterfaceEnv(FileName+2); + return (EFI_SUCCESS); + } + + // + // We are opening a regular file. + // + DevicePath = EfiShellGetDevicePathFromFilePath(FileName); + + if (DevicePath == NULL) { + return (EFI_NOT_FOUND); + } + + // + // Copy the device path, open the file, then free the memory + // + Status = InternalOpenFileDevicePath(DevicePath, FileHandle, OpenMode, 0); // 0 = no specific file attributes + FreePool(DevicePath); + + return(Status); +} + +/** + Deletes the file specified by the file name. + + This function deletes a file. + + @param FileName Points to the NULL-terminated file name. + + @retval EFI_SUCCESS The file was closed and deleted, and the handle was closed. + @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted. + @sa EfiShellCreateFile +**/ +EFI_STATUS +EFIAPI +EfiShellDeleteFileByName( + IN CONST CHAR16 *FileName + ) +{ + SHELL_FILE_HANDLE FileHandle; + EFI_STATUS Status; + + FileHandle = NULL; + + // + // get a handle to the file + // + Status = EfiShellCreateFile(FileName, + 0, + &FileHandle); + if (EFI_ERROR(Status)) { + return (Status); + } + // + // now delete the file + // + ShellFileHandleRemove(FileHandle); + return (ShellInfoObject.NewEfiShellProtocol->DeleteFile(FileHandle)); +} + +/** + Disables the page break output mode. +**/ +VOID +EFIAPI +EfiShellDisablePageBreak ( + VOID + ) +{ + ShellInfoObject.PageBreakEnabled = FALSE; +} + +/** + Enables the page break output mode. +**/ +VOID +EFIAPI +EfiShellEnablePageBreak ( + VOID + ) +{ + ShellInfoObject.PageBreakEnabled = TRUE; +} + +/** + internal worker function to load and run an image via device path. + + @param ParentImageHandle A handle of the image that is executing the specified + command line. + @param DevicePath device path of the file to execute + @param CommandLine Points to the NULL-terminated UCS-2 encoded string + containing the command line. If NULL then the command- + line will be empty. + @param Environment Points to a NULL-terminated array of environment + variables with the format 'x=y', where x is the + environment variable name and y is the value. If this + is NULL, then the current shell environment is used. + + @param[out] StartImageStatus Returned status from gBS->StartImage. + + @retval EFI_SUCCESS The command executed successfully. The status code + returned by the command is pointed to by StatusCode. + @retval EFI_INVALID_PARAMETER The parameters are invalid. + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_UNSUPPORTED Nested shell invocations are not allowed. +**/ +EFI_STATUS +InternalShellExecuteDevicePath( + IN CONST EFI_HANDLE *ParentImageHandle, + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN CONST CHAR16 *CommandLine OPTIONAL, + IN CONST CHAR16 **Environment OPTIONAL, + OUT EFI_STATUS *StartImageStatus OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_STATUS StartStatus; + EFI_STATUS CleanupStatus; + EFI_HANDLE NewHandle; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + LIST_ENTRY OrigEnvs; + EFI_SHELL_PARAMETERS_PROTOCOL ShellParamsProtocol; + CHAR16 *ImagePath; + UINTN Index; + CHAR16 *Walker; + CHAR16 *NewCmdLine; + + if (ParentImageHandle == NULL) { + return (EFI_INVALID_PARAMETER); + } + + InitializeListHead(&OrigEnvs); + ZeroMem(&ShellParamsProtocol, sizeof(EFI_SHELL_PARAMETERS_PROTOCOL)); + + NewHandle = NULL; + + NewCmdLine = AllocateCopyPool (StrSize (CommandLine), CommandLine); + if (NewCmdLine == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + for (Walker = NewCmdLine; Walker != NULL && *Walker != CHAR_NULL ; Walker++) { + if (*Walker == L'^' && *(Walker+1) == L'#') { + CopyMem(Walker, Walker+1, StrSize(Walker) - sizeof(Walker[0])); + } + } + + // + // Load the image with: + // FALSE - not from boot manager and NULL, 0 being not already in memory + // + Status = gBS->LoadImage( + FALSE, + *ParentImageHandle, + (EFI_DEVICE_PATH_PROTOCOL*)DevicePath, + NULL, + 0, + &NewHandle); + + if (EFI_ERROR(Status)) { + if (NewHandle != NULL) { + gBS->UnloadImage(NewHandle); + } + FreePool (NewCmdLine); + return (Status); + } + Status = gBS->OpenProtocol( + NewHandle, + &gEfiLoadedImageProtocolGuid, + (VOID**)&LoadedImage, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + if (!EFI_ERROR(Status)) { + // + // If the image is not an app abort it. + // + if (LoadedImage->ImageCodeType != EfiLoaderCode){ + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_SHELL_IMAGE_NOT_APP), + ShellInfoObject.HiiHandle + ); + goto UnloadImage; + } + + ASSERT(LoadedImage->LoadOptionsSize == 0); + if (NewCmdLine != NULL) { + LoadedImage->LoadOptionsSize = (UINT32)StrSize(NewCmdLine); + LoadedImage->LoadOptions = (VOID*)NewCmdLine; + } + + // + // Save our current environment settings for later restoration if necessary + // + if (Environment != NULL) { + Status = GetEnvironmentVariableList(&OrigEnvs); + if (!EFI_ERROR(Status)) { + Status = SetEnvironmentVariables(Environment); + } + } + + // + // Initialize and install a shell parameters protocol on the image. + // + ShellParamsProtocol.StdIn = ShellInfoObject.NewShellParametersProtocol->StdIn; + ShellParamsProtocol.StdOut = ShellInfoObject.NewShellParametersProtocol->StdOut; + ShellParamsProtocol.StdErr = ShellInfoObject.NewShellParametersProtocol->StdErr; + Status = UpdateArgcArgv(&ShellParamsProtocol, NewCmdLine, Efi_Application, NULL, NULL); + if (EFI_ERROR (Status)) { + goto UnloadImage; + } + + // + // Replace Argv[0] with the full path of the binary we're executing: + // If the command line was "foo", the binary might be called "foo.efi". + // "The first entry in [Argv] is always the full file path of the + // executable" - UEFI Shell Spec section 2.3 + // + ImagePath = EfiShellGetFilePathFromDevicePath (DevicePath); + // The image we're executing isn't necessarily in a filesystem - it might + // be memory mapped. In this case EfiShellGetFilePathFromDevicePath will + // return NULL, and we'll leave Argv[0] as UpdateArgcArgv set it. + if (ImagePath != NULL) { + if (ShellParamsProtocol.Argv == NULL) { + // Command line was empty or null. + // (UpdateArgcArgv sets Argv to NULL when CommandLine is "" or NULL) + ShellParamsProtocol.Argv = AllocatePool (sizeof (CHAR16 *)); + if (ShellParamsProtocol.Argv == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto UnloadImage; + } + ShellParamsProtocol.Argc = 1; + } else { + // Free the string UpdateArgcArgv put in Argv[0]; + FreePool (ShellParamsProtocol.Argv[0]); + } + ShellParamsProtocol.Argv[0] = ImagePath; + } + + Status = gBS->InstallProtocolInterface(&NewHandle, &gEfiShellParametersProtocolGuid, EFI_NATIVE_INTERFACE, &ShellParamsProtocol); + ASSERT_EFI_ERROR(Status); + + ///@todo initialize and install ShellInterface protocol on the new image for compatibility if - PcdGetBool(PcdShellSupportOldProtocols) + + // + // now start the image and if the caller wanted the return code pass it to them... + // + if (!EFI_ERROR(Status)) { + StartStatus = gBS->StartImage( + NewHandle, + 0, + NULL + ); + if (StartImageStatus != NULL) { + *StartImageStatus = StartStatus; + } + + CleanupStatus = gBS->UninstallProtocolInterface( + NewHandle, + &gEfiShellParametersProtocolGuid, + &ShellParamsProtocol + ); + ASSERT_EFI_ERROR(CleanupStatus); + + goto FreeAlloc; + } + +UnloadImage: + // Unload image - We should only get here if we didn't call StartImage + gBS->UnloadImage (NewHandle); + +FreeAlloc: + // Free Argv (Allocated in UpdateArgcArgv) + if (ShellParamsProtocol.Argv != NULL) { + for (Index = 0; Index < ShellParamsProtocol.Argc; Index++) { + if (ShellParamsProtocol.Argv[Index] != NULL) { + FreePool (ShellParamsProtocol.Argv[Index]); + } + } + FreePool (ShellParamsProtocol.Argv); + } + } + + // Restore environment variables + if (!IsListEmpty(&OrigEnvs)) { + CleanupStatus = SetEnvironmentVariableList(&OrigEnvs); + ASSERT_EFI_ERROR (CleanupStatus); + } + + FreePool (NewCmdLine); + + return(Status); +} + +/** + internal worker function to load and run an image in the current shell. + + @param CommandLine Points to the NULL-terminated UCS-2 encoded string + containing the command line. If NULL then the command- + line will be empty. + @param Environment Points to a NULL-terminated array of environment + variables with the format 'x=y', where x is the + environment variable name and y is the value. If this + is NULL, then the current shell environment is used. + + @param[out] StartImageStatus Returned status from the command line. + + @retval EFI_SUCCESS The command executed successfully. The status code + returned by the command is pointed to by StatusCode. + @retval EFI_INVALID_PARAMETER The parameters are invalid. + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_UNSUPPORTED Nested shell invocations are not allowed. +**/ +EFI_STATUS +InternalShellExecute( + IN CONST CHAR16 *CommandLine OPTIONAL, + IN CONST CHAR16 **Environment OPTIONAL, + OUT EFI_STATUS *StartImageStatus OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_STATUS CleanupStatus; + LIST_ENTRY OrigEnvs; + + InitializeListHead(&OrigEnvs); + + // + // Save our current environment settings for later restoration if necessary + // + if (Environment != NULL) { + Status = GetEnvironmentVariableList(&OrigEnvs); + if (!EFI_ERROR(Status)) { + Status = SetEnvironmentVariables(Environment); + } else { + return Status; + } + } + + Status = RunShellCommand(CommandLine, StartImageStatus); + + // Restore environment variables + if (!IsListEmpty(&OrigEnvs)) { + CleanupStatus = SetEnvironmentVariableList(&OrigEnvs); + ASSERT_EFI_ERROR (CleanupStatus); + } + + return(Status); +} + +/** + Determine if the UEFI Shell is currently running with nesting enabled or disabled. + + @retval FALSE nesting is required + @retval other nesting is enabled +**/ +STATIC +BOOLEAN +NestingEnabled( + VOID +) +{ + EFI_STATUS Status; + CHAR16 *Temp; + CHAR16 *Temp2; + UINTN TempSize; + BOOLEAN RetVal; + + RetVal = TRUE; + Temp = NULL; + Temp2 = NULL; + + if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoNest) { + TempSize = 0; + Temp = NULL; + Status = SHELL_GET_ENVIRONMENT_VARIABLE(mNoNestingEnvVarName, &TempSize, Temp); + if (Status == EFI_BUFFER_TOO_SMALL) { + Temp = AllocateZeroPool(TempSize + sizeof(CHAR16)); + if (Temp != NULL) { + Status = SHELL_GET_ENVIRONMENT_VARIABLE(mNoNestingEnvVarName, &TempSize, Temp); + } + } + Temp2 = StrnCatGrow(&Temp2, NULL, mNoNestingTrue, 0); + if (Temp != NULL && Temp2 != NULL && StringNoCaseCompare(&Temp, &Temp2) == 0) { + // + // Use the no nesting method. + // + RetVal = FALSE; + } + } + + SHELL_FREE_NON_NULL(Temp); + SHELL_FREE_NON_NULL(Temp2); + return (RetVal); +} + +/** + Execute the command line. + + This function creates a nested instance of the shell and executes the specified + command (CommandLine) with the specified environment (Environment). Upon return, + the status code returned by the specified command is placed in StatusCode. + + If Environment is NULL, then the current environment is used and all changes made + by the commands executed will be reflected in the current environment. If the + Environment is non-NULL, then the changes made will be discarded. + + The CommandLine is executed from the current working directory on the current + device. + + @param ParentImageHandle A handle of the image that is executing the specified + command line. + @param CommandLine Points to the NULL-terminated UCS-2 encoded string + containing the command line. If NULL then the command- + line will be empty. + @param Environment Points to a NULL-terminated array of environment + variables with the format 'x=y', where x is the + environment variable name and y is the value. If this + is NULL, then the current shell environment is used. + @param StatusCode Points to the status code returned by the CommandLine. + + @retval EFI_SUCCESS The command executed successfully. The status code + returned by the command is pointed to by StatusCode. + @retval EFI_INVALID_PARAMETER The parameters are invalid. + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_UNSUPPORTED Nested shell invocations are not allowed. + @retval EFI_UNSUPPORTED The support level required for this function is not present. + + @sa InternalShellExecuteDevicePath +**/ +EFI_STATUS +EFIAPI +EfiShellExecute( + IN EFI_HANDLE *ParentImageHandle, + IN CHAR16 *CommandLine OPTIONAL, + IN CHAR16 **Environment OPTIONAL, + OUT EFI_STATUS *StatusCode OPTIONAL + ) +{ + EFI_STATUS Status; + CHAR16 *Temp; + EFI_DEVICE_PATH_PROTOCOL *DevPath; + UINTN Size; + + if ((PcdGet8(PcdShellSupportLevel) < 1)) { + return (EFI_UNSUPPORTED); + } + + if (NestingEnabled()) { + DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath); + + DEBUG_CODE_BEGIN(); + Temp = ConvertDevicePathToText(ShellInfoObject.FileDevPath, TRUE, TRUE); + FreePool(Temp); + Temp = ConvertDevicePathToText(ShellInfoObject.ImageDevPath, TRUE, TRUE); + FreePool(Temp); + Temp = ConvertDevicePathToText(DevPath, TRUE, TRUE); + FreePool(Temp); + DEBUG_CODE_END(); + + Temp = NULL; + Size = 0; + ASSERT((Temp == NULL && Size == 0) || (Temp != NULL)); + StrnCatGrow(&Temp, &Size, L"Shell.efi -exit ", 0); + StrnCatGrow(&Temp, &Size, CommandLine, 0); + + Status = InternalShellExecuteDevicePath( + ParentImageHandle, + DevPath, + Temp, + (CONST CHAR16**)Environment, + StatusCode); + + // + // de-allocate and return + // + FreePool(DevPath); + FreePool(Temp); + } else { + Status = InternalShellExecute( + (CONST CHAR16*)CommandLine, + (CONST CHAR16**)Environment, + StatusCode); + } + + return(Status); +} + +/** + Utility cleanup function for EFI_SHELL_FILE_INFO objects. + + 1) frees all pointers (non-NULL) + 2) Closes the SHELL_FILE_HANDLE + + @param FileListNode pointer to the list node to free +**/ +VOID +InternalFreeShellFileInfoNode( + IN EFI_SHELL_FILE_INFO *FileListNode + ) +{ + if (FileListNode->Info != NULL) { + FreePool((VOID*)FileListNode->Info); + } + if (FileListNode->FileName != NULL) { + FreePool((VOID*)FileListNode->FileName); + } + if (FileListNode->FullName != NULL) { + FreePool((VOID*)FileListNode->FullName); + } + if (FileListNode->Handle != NULL) { + ShellInfoObject.NewEfiShellProtocol->CloseFile(FileListNode->Handle); + } + FreePool(FileListNode); +} +/** + Frees the file list. + + This function cleans up the file list and any related data structures. It has no + impact on the files themselves. + + @param FileList The file list to free. Type EFI_SHELL_FILE_INFO is + defined in OpenFileList() + + @retval EFI_SUCCESS Free the file list successfully. + @retval EFI_INVALID_PARAMETER FileList was NULL or *FileList was NULL; +**/ +EFI_STATUS +EFIAPI +EfiShellFreeFileList( + IN EFI_SHELL_FILE_INFO **FileList + ) +{ + EFI_SHELL_FILE_INFO *ShellFileListItem; + + if (FileList == NULL || *FileList == NULL) { + return (EFI_INVALID_PARAMETER); + } + + for ( ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(*FileList)->Link) + ; !IsListEmpty(&(*FileList)->Link) + ; ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(*FileList)->Link) + ){ + RemoveEntryList(&ShellFileListItem->Link); + InternalFreeShellFileInfoNode(ShellFileListItem); + } + InternalFreeShellFileInfoNode(*FileList); + *FileList = NULL; + return(EFI_SUCCESS); +} + +/** + Deletes the duplicate file names files in the given file list. + + This function deletes the reduplicate files in the given file list. + + @param FileList A pointer to the first entry in the file list. + + @retval EFI_SUCCESS Always success. + @retval EFI_INVALID_PARAMETER FileList was NULL or *FileList was NULL; +**/ +EFI_STATUS +EFIAPI +EfiShellRemoveDupInFileList( + IN EFI_SHELL_FILE_INFO **FileList + ) +{ + EFI_STATUS Status; + EFI_SHELL_FILE_INFO *Duplicates; + EFI_SHELL_FILE_INFO *ShellFileListItem; + EFI_SHELL_FILE_INFO *ShellFileListItem2; + EFI_SHELL_FILE_INFO *TempNode; + + if (FileList == NULL || *FileList == NULL) { + return (EFI_INVALID_PARAMETER); + } + + Status = ShellSortFileList ( + FileList, + &Duplicates, + ShellSortFileListByFullName + ); + if (!EFI_ERROR (Status)) { + EfiShellFreeFileList (&Duplicates); + return EFI_SUCCESS; + } + // + // Fall back to the slow method that needs no extra memory, and so cannot + // fail. + // + for ( ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(*FileList)->Link) + ; !IsNull(&(*FileList)->Link, &ShellFileListItem->Link) + ; ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetNextNode(&(*FileList)->Link, &ShellFileListItem->Link) + ){ + for ( ShellFileListItem2 = (EFI_SHELL_FILE_INFO*)GetNextNode(&(*FileList)->Link, &ShellFileListItem->Link) + ; !IsNull(&(*FileList)->Link, &ShellFileListItem2->Link) + ; ShellFileListItem2 = (EFI_SHELL_FILE_INFO*)GetNextNode(&(*FileList)->Link, &ShellFileListItem2->Link) + ){ + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)ShellFileListItem->FullName, + (CHAR16*)ShellFileListItem2->FullName) == 0 + ){ + TempNode = (EFI_SHELL_FILE_INFO *)GetPreviousNode( + &(*FileList)->Link, + &ShellFileListItem2->Link + ); + RemoveEntryList(&ShellFileListItem2->Link); + InternalFreeShellFileInfoNode(ShellFileListItem2); + // Set ShellFileListItem2 to PreviousNode so we don't access Freed + // memory in GetNextNode in the loop expression above. + ShellFileListItem2 = TempNode; + } + } + } + return (EFI_SUCCESS); +} + +// +// This is the same structure as the external version, but it has no CONST qualifiers. +// +typedef struct { + LIST_ENTRY Link; ///< Linked list members. + EFI_STATUS Status; ///< Status of opening the file. Valid only if Handle != NULL. + CHAR16 *FullName; ///< Fully qualified filename. + CHAR16 *FileName; ///< name of this file. + SHELL_FILE_HANDLE Handle; ///< Handle for interacting with the opened file or NULL if closed. + EFI_FILE_INFO *Info; ///< Pointer to the FileInfo struct for this file or NULL. +} EFI_SHELL_FILE_INFO_NO_CONST; + +/** + Allocates and duplicates a EFI_SHELL_FILE_INFO node. + + @param[in] Node The node to copy from. + @param[in] Save TRUE to set Node->Handle to NULL, FALSE otherwise. + + @retval NULL a memory allocation error occurred + @return != NULL a pointer to the new node +**/ +EFI_SHELL_FILE_INFO* +InternalDuplicateShellFileInfo( + IN EFI_SHELL_FILE_INFO *Node, + IN BOOLEAN Save + ) +{ + EFI_SHELL_FILE_INFO_NO_CONST *NewNode; + + // + // try to confirm that the objects are in sync + // + ASSERT(sizeof(EFI_SHELL_FILE_INFO_NO_CONST) == sizeof(EFI_SHELL_FILE_INFO)); + + NewNode = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO)); + if (NewNode == NULL) { + return (NULL); + } + NewNode->FullName = AllocateCopyPool(StrSize(Node->FullName), Node->FullName); + NewNode->FileName = AllocateCopyPool(StrSize(Node->FileName), Node->FileName); + NewNode->Info = AllocateCopyPool((UINTN)Node->Info->Size, Node->Info); + if ( NewNode->FullName == NULL + || NewNode->FileName == NULL + || NewNode->Info == NULL + ){ + SHELL_FREE_NON_NULL(NewNode->FullName); + SHELL_FREE_NON_NULL(NewNode->FileName); + SHELL_FREE_NON_NULL(NewNode->Info); + SHELL_FREE_NON_NULL(NewNode); + return(NULL); + } + NewNode->Status = Node->Status; + NewNode->Handle = Node->Handle; + if (!Save) { + Node->Handle = NULL; + } + + return((EFI_SHELL_FILE_INFO*)NewNode); +} + +/** + Allocates and populates a EFI_SHELL_FILE_INFO structure. if any memory operation + failed it will return NULL. + + @param[in] BasePath the Path to prepend onto filename for FullPath + @param[in] Status Status member initial value. + @param[in] FileName FileName member initial value. + @param[in] Handle Handle member initial value. + @param[in] Info Info struct to copy. + + @retval NULL An error occurred. + @return a pointer to the newly allocated structure. +**/ +EFI_SHELL_FILE_INFO * +CreateAndPopulateShellFileInfo( + IN CONST CHAR16 *BasePath, + IN CONST EFI_STATUS Status, + IN CONST CHAR16 *FileName, + IN CONST SHELL_FILE_HANDLE Handle, + IN CONST EFI_FILE_INFO *Info + ) +{ + EFI_SHELL_FILE_INFO *ShellFileListItem; + CHAR16 *TempString; + UINTN Size; + + TempString = NULL; + Size = 0; + + ShellFileListItem = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO)); + if (ShellFileListItem == NULL) { + return (NULL); + } + if (Info != NULL && Info->Size != 0) { + ShellFileListItem->Info = AllocateZeroPool((UINTN)Info->Size); + if (ShellFileListItem->Info == NULL) { + FreePool(ShellFileListItem); + return (NULL); + } + CopyMem(ShellFileListItem->Info, Info, (UINTN)Info->Size); + } else { + ShellFileListItem->Info = NULL; + } + if (FileName != NULL) { + ASSERT(TempString == NULL); + ShellFileListItem->FileName = StrnCatGrow(&TempString, 0, FileName, 0); + if (ShellFileListItem->FileName == NULL) { + FreePool(ShellFileListItem->Info); + FreePool(ShellFileListItem); + return (NULL); + } + } else { + ShellFileListItem->FileName = NULL; + } + Size = 0; + TempString = NULL; + if (BasePath != NULL) { + ASSERT((TempString == NULL && Size == 0) || (TempString != NULL)); + TempString = StrnCatGrow(&TempString, &Size, BasePath, 0); + if (TempString == NULL) { + FreePool((VOID*)ShellFileListItem->FileName); + SHELL_FREE_NON_NULL(ShellFileListItem->Info); + FreePool(ShellFileListItem); + return (NULL); + } + } + if (ShellFileListItem->FileName != NULL) { + ASSERT((TempString == NULL && Size == 0) || (TempString != NULL)); + TempString = StrnCatGrow(&TempString, &Size, ShellFileListItem->FileName, 0); + if (TempString == NULL) { + FreePool((VOID*)ShellFileListItem->FileName); + FreePool(ShellFileListItem->Info); + FreePool(ShellFileListItem); + return (NULL); + } + } + + TempString = PathCleanUpDirectories(TempString); + + ShellFileListItem->FullName = TempString; + ShellFileListItem->Status = Status; + ShellFileListItem->Handle = Handle; + + return (ShellFileListItem); +} + +/** + Find all files in a specified directory. + + @param FileDirHandle Handle of the directory to search. + @param FileList On return, points to the list of files in the directory + or NULL if there are no files in the directory. + + @retval EFI_SUCCESS File information was returned successfully. + @retval EFI_VOLUME_CORRUPTED The file system structures have been corrupted. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_NO_MEDIA The device media is not present. + @retval EFI_INVALID_PARAMETER The FileDirHandle was not a directory. + @return An error from FileHandleGetFileName(). +**/ +EFI_STATUS +EFIAPI +EfiShellFindFilesInDir( + IN SHELL_FILE_HANDLE FileDirHandle, + OUT EFI_SHELL_FILE_INFO **FileList + ) +{ + EFI_SHELL_FILE_INFO *ShellFileList; + EFI_SHELL_FILE_INFO *ShellFileListItem; + EFI_FILE_INFO *FileInfo; + EFI_STATUS Status; + BOOLEAN NoFile; + CHAR16 *TempString; + CHAR16 *BasePath; + UINTN Size; + CHAR16 *TempSpot; + + BasePath = NULL; + Status = FileHandleGetFileName(FileDirHandle, &BasePath); + if (EFI_ERROR(Status)) { + return (Status); + } + + if (ShellFileHandleGetPath(FileDirHandle) != NULL) { + TempString = NULL; + Size = 0; + TempString = StrnCatGrow(&TempString, &Size, ShellFileHandleGetPath(FileDirHandle), 0); + if (TempString == NULL) { + SHELL_FREE_NON_NULL(BasePath); + return (EFI_OUT_OF_RESOURCES); + } + TempSpot = StrStr(TempString, L";"); + + if (TempSpot != NULL) { + *TempSpot = CHAR_NULL; + } + + TempString = StrnCatGrow(&TempString, &Size, BasePath, 0); + if (TempString == NULL) { + SHELL_FREE_NON_NULL(BasePath); + return (EFI_OUT_OF_RESOURCES); + } + SHELL_FREE_NON_NULL(BasePath); + BasePath = TempString; + } + + NoFile = FALSE; + ShellFileList = NULL; + ShellFileListItem = NULL; + FileInfo = NULL; + Status = EFI_SUCCESS; + + + for ( Status = FileHandleFindFirstFile(FileDirHandle, &FileInfo) + ; !EFI_ERROR(Status) && !NoFile + ; Status = FileHandleFindNextFile(FileDirHandle, FileInfo, &NoFile) + ){ + if (ShellFileList == NULL) { + ShellFileList = (EFI_SHELL_FILE_INFO*)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO)); + if (ShellFileList == NULL) { + SHELL_FREE_NON_NULL (BasePath); + return EFI_OUT_OF_RESOURCES; + } + InitializeListHead(&ShellFileList->Link); + } + // + // allocate a new EFI_SHELL_FILE_INFO and populate it... + // + ShellFileListItem = CreateAndPopulateShellFileInfo( + BasePath, + EFI_SUCCESS, // success since we didn't fail to open it... + FileInfo->FileName, + NULL, // no handle since not open + FileInfo); + if (ShellFileListItem == NULL) { + Status = EFI_OUT_OF_RESOURCES; + // + // Free resources outside the loop. + // + break; + } + InsertTailList(&ShellFileList->Link, &ShellFileListItem->Link); + } + if (EFI_ERROR(Status)) { + EfiShellFreeFileList(&ShellFileList); + *FileList = NULL; + } else { + *FileList = ShellFileList; + } + SHELL_FREE_NON_NULL(BasePath); + return(Status); +} + +/** + Get the GUID value from a human readable name. + + If GuidName is a known GUID name, then update Guid to have the correct value for + that GUID. + + This function is only available when the major and minor versions in the + EfiShellProtocol are greater than or equal to 2 and 1, respectively. + + @param[in] GuidName A pointer to the localized name for the GUID being queried. + @param[out] Guid A pointer to the GUID structure to be filled in. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_INVALID_PARAMETER Guid was NULL. + @retval EFI_INVALID_PARAMETER GuidName was NULL. + @retval EFI_NOT_FOUND GuidName is not a known GUID Name. +**/ +EFI_STATUS +EFIAPI +EfiShellGetGuidFromName( + IN CONST CHAR16 *GuidName, + OUT EFI_GUID *Guid + ) +{ + EFI_GUID *NewGuid; + EFI_STATUS Status; + + if (Guid == NULL || GuidName == NULL) { + return (EFI_INVALID_PARAMETER); + } + + Status = GetGuidFromStringName(GuidName, NULL, &NewGuid); + + if (!EFI_ERROR(Status)) { + CopyGuid(Guid, NewGuid); + } + + return (Status); +} + +/** + Get the human readable name for a GUID from the value. + + If Guid is assigned a name, then update *GuidName to point to the name. The callee + should not modify the value. + + This function is only available when the major and minor versions in the + EfiShellProtocol are greater than or equal to 2 and 1, respectively. + + @param[in] Guid A pointer to the GUID being queried. + @param[out] GuidName A pointer to a pointer the localized to name for the GUID being requested + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_INVALID_PARAMETER Guid was NULL. + @retval EFI_INVALID_PARAMETER GuidName was NULL. + @retval EFI_NOT_FOUND Guid is not assigned a name. +**/ +EFI_STATUS +EFIAPI +EfiShellGetGuidName( + IN CONST EFI_GUID *Guid, + OUT CONST CHAR16 **GuidName + ) +{ + CHAR16 *Name; + + if (Guid == NULL || GuidName == NULL) { + return (EFI_INVALID_PARAMETER); + } + + Name = GetStringNameFromGuid(Guid, NULL); + if (Name == NULL || StrLen(Name) == 0) { + SHELL_FREE_NON_NULL(Name); + return (EFI_NOT_FOUND); + } + + *GuidName = AddBufferToFreeList(Name); + + return (EFI_SUCCESS); +} + + + +/** + If FileHandle is a directory then the function reads from FileHandle and reads in + each of the FileInfo structures. If one of them matches the Pattern's first + "level" then it opens that handle and calls itself on that handle. + + If FileHandle is a file and matches all of the remaining Pattern (which would be + on its last node), then add a EFI_SHELL_FILE_INFO object for this file to fileList. + + Upon a EFI_SUCCESS return fromt he function any the caller is responsible to call + FreeFileList with FileList. + + @param[in] FilePattern The FilePattern to check against. + @param[in] UnicodeCollation The pointer to EFI_UNICODE_COLLATION_PROTOCOL structure + @param[in] FileHandle The FileHandle to start with + @param[in, out] FileList pointer to pointer to list of found files. + @param[in] ParentNode The node for the parent. Same file as identified by HANDLE. + @param[in] MapName The file system name this file is on. + + @retval EFI_SUCCESS all files were found and the FileList contains a list. + @retval EFI_NOT_FOUND no files were found + @retval EFI_OUT_OF_RESOURCES a memory allocation failed +**/ +EFI_STATUS +ShellSearchHandle( + IN CONST CHAR16 *FilePattern, + IN EFI_UNICODE_COLLATION_PROTOCOL *UnicodeCollation, + IN SHELL_FILE_HANDLE FileHandle, + IN OUT EFI_SHELL_FILE_INFO **FileList, + IN CONST EFI_SHELL_FILE_INFO *ParentNode OPTIONAL, + IN CONST CHAR16 *MapName + ) +{ + EFI_STATUS Status; + CONST CHAR16 *NextFilePatternStart; + CHAR16 *CurrentFilePattern; + EFI_SHELL_FILE_INFO *ShellInfo; + EFI_SHELL_FILE_INFO *ShellInfoNode; + EFI_SHELL_FILE_INFO *NewShellNode; + EFI_FILE_INFO *FileInfo; + BOOLEAN Directory; + CHAR16 *NewFullName; + UINTN Size; + + if ( FilePattern == NULL + || UnicodeCollation == NULL + || FileList == NULL + ){ + return (EFI_INVALID_PARAMETER); + } + ShellInfo = NULL; + CurrentFilePattern = NULL; + + if (*FilePattern == L'\\') { + FilePattern++; + } + + for( NextFilePatternStart = FilePattern + ; *NextFilePatternStart != CHAR_NULL && *NextFilePatternStart != L'\\' + ; NextFilePatternStart++); + + CurrentFilePattern = AllocateZeroPool((NextFilePatternStart-FilePattern+1)*sizeof(CHAR16)); + if (CurrentFilePattern == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + StrnCpyS(CurrentFilePattern, NextFilePatternStart-FilePattern+1, FilePattern, NextFilePatternStart-FilePattern); + + if (CurrentFilePattern[0] == CHAR_NULL + &&NextFilePatternStart[0] == CHAR_NULL + ){ + // + // we want the parent or root node (if no parent) + // + if (ParentNode == NULL) { + // + // We want the root node. create the node. + // + FileInfo = FileHandleGetInfo(FileHandle); + NewShellNode = CreateAndPopulateShellFileInfo( + MapName, + EFI_SUCCESS, + L"\\", + FileHandle, + FileInfo + ); + SHELL_FREE_NON_NULL(FileInfo); + } else { + // + // Add the current parameter FileHandle to the list, then end... + // + NewShellNode = InternalDuplicateShellFileInfo((EFI_SHELL_FILE_INFO*)ParentNode, TRUE); + } + if (NewShellNode == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + NewShellNode->Handle = NULL; + if (*FileList == NULL) { + *FileList = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO)); + InitializeListHead(&((*FileList)->Link)); + } + + // + // Add to the returning to use list + // + InsertTailList(&(*FileList)->Link, &NewShellNode->Link); + + Status = EFI_SUCCESS; + } + } else { + Status = EfiShellFindFilesInDir(FileHandle, &ShellInfo); + + if (!EFI_ERROR(Status)){ + if (StrStr(NextFilePatternStart, L"\\") != NULL){ + Directory = TRUE; + } else { + Directory = FALSE; + } + for ( ShellInfoNode = (EFI_SHELL_FILE_INFO*)GetFirstNode(&ShellInfo->Link) + ; !IsNull (&ShellInfo->Link, &ShellInfoNode->Link) + ; ShellInfoNode = (EFI_SHELL_FILE_INFO*)GetNextNode(&ShellInfo->Link, &ShellInfoNode->Link) + ){ + if (UnicodeCollation->MetaiMatch(UnicodeCollation, (CHAR16*)ShellInfoNode->FileName, CurrentFilePattern)){ + if (ShellInfoNode->FullName != NULL && StrStr(ShellInfoNode->FullName, L":") == NULL) { + Size = StrSize (ShellInfoNode->FullName) + StrSize (MapName); + NewFullName = AllocateZeroPool(Size); + if (NewFullName == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + StrCpyS(NewFullName, Size / sizeof(CHAR16), MapName); + StrCatS(NewFullName, Size / sizeof(CHAR16), ShellInfoNode->FullName); + FreePool ((VOID *) ShellInfoNode->FullName); + ShellInfoNode->FullName = NewFullName; + } + } + if (Directory && !EFI_ERROR(Status) && ShellInfoNode->FullName != NULL && ShellInfoNode->FileName != NULL){ + // + // should be a directory + // + + // + // don't open the . and .. directories + // + if ( (StrCmp(ShellInfoNode->FileName, L".") != 0) + && (StrCmp(ShellInfoNode->FileName, L"..") != 0) + ){ + // + // + // + if (EFI_ERROR(Status)) { + break; + } + // + // Open the directory since we need that handle in the next recursion. + // + ShellInfoNode->Status = EfiShellOpenFileByName (ShellInfoNode->FullName, &ShellInfoNode->Handle, EFI_FILE_MODE_READ); + + // + // recurse with the next part of the pattern + // + Status = ShellSearchHandle(NextFilePatternStart, UnicodeCollation, ShellInfoNode->Handle, FileList, ShellInfoNode, MapName); + EfiShellClose(ShellInfoNode->Handle); + ShellInfoNode->Handle = NULL; + } + } else if (!EFI_ERROR(Status)) { + // + // should be a file + // + + // + // copy the information we need into a new Node + // + NewShellNode = InternalDuplicateShellFileInfo(ShellInfoNode, FALSE); + if (NewShellNode == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } + if (*FileList == NULL) { + *FileList = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO)); + InitializeListHead(&((*FileList)->Link)); + } + + // + // Add to the returning to use list + // + InsertTailList(&(*FileList)->Link, &NewShellNode->Link); + } + } + if (EFI_ERROR(Status)) { + break; + } + } + if (EFI_ERROR(Status)) { + EfiShellFreeFileList(&ShellInfo); + } else { + Status = EfiShellFreeFileList(&ShellInfo); + } + } + } + + if (*FileList == NULL || (*FileList != NULL && IsListEmpty(&(*FileList)->Link))) { + Status = EFI_NOT_FOUND; + } + + FreePool(CurrentFilePattern); + return (Status); +} + +/** + Find files that match a specified pattern. + + This function searches for all files and directories that match the specified + FilePattern. The FilePattern can contain wild-card characters. The resulting file + information is placed in the file list FileList. + + Wildcards are processed + according to the rules specified in UEFI Shell 2.0 spec section 3.7.1. + + The files in the file list are not opened. The OpenMode field is set to 0 and the FileInfo + field is set to NULL. + + if *FileList is not NULL then it must be a pre-existing and properly initialized list. + + @param FilePattern Points to a NULL-terminated shell file path, including wildcards. + @param FileList On return, points to the start of a file list containing the names + of all matching files or else points to NULL if no matching files + were found. only on a EFI_SUCCESS return will; this be non-NULL. + + @retval EFI_SUCCESS Files found. FileList is a valid list. + @retval EFI_NOT_FOUND No files found. + @retval EFI_NO_MEDIA The device has no media + @retval EFI_DEVICE_ERROR The device reported an error + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted +**/ +EFI_STATUS +EFIAPI +EfiShellFindFiles( + IN CONST CHAR16 *FilePattern, + OUT EFI_SHELL_FILE_INFO **FileList + ) +{ + EFI_STATUS Status; + CHAR16 *PatternCopy; + CHAR16 *PatternCurrentLocation; + EFI_DEVICE_PATH_PROTOCOL *RootDevicePath; + SHELL_FILE_HANDLE RootFileHandle; + CHAR16 *MapName; + UINTN Count; + + if ( FilePattern == NULL + || FileList == NULL + || StrStr(FilePattern, L":") == NULL + ){ + return (EFI_INVALID_PARAMETER); + } + Status = EFI_SUCCESS; + RootDevicePath = NULL; + RootFileHandle = NULL; + MapName = NULL; + PatternCopy = AllocateCopyPool(StrSize(FilePattern), FilePattern); + if (PatternCopy == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + PatternCopy = PathCleanUpDirectories(PatternCopy); + + Count = StrStr(PatternCopy, L":") - PatternCopy + 1; + ASSERT (Count <= StrLen (PatternCopy)); + + ASSERT(MapName == NULL); + MapName = StrnCatGrow(&MapName, NULL, PatternCopy, Count); + if (MapName == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + RootDevicePath = EfiShellGetDevicePathFromFilePath(PatternCopy); + if (RootDevicePath == NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + Status = EfiShellOpenRoot(RootDevicePath, &RootFileHandle); + if (!EFI_ERROR(Status)) { + for ( PatternCurrentLocation = PatternCopy + ; *PatternCurrentLocation != ':' + ; PatternCurrentLocation++); + PatternCurrentLocation++; + Status = ShellSearchHandle(PatternCurrentLocation, gUnicodeCollation, RootFileHandle, FileList, NULL, MapName); + EfiShellClose(RootFileHandle); + } + FreePool(RootDevicePath); + } + } + + SHELL_FREE_NON_NULL(PatternCopy); + SHELL_FREE_NON_NULL(MapName); + + return(Status); +} + +/** + Opens the files that match the path specified. + + This function opens all of the files specified by Path. Wildcards are processed + according to the rules specified in UEFI Shell 2.0 spec section 3.7.1. Each + matching file has an EFI_SHELL_FILE_INFO structure created in a linked list. + + @param Path A pointer to the path string. + @param OpenMode Specifies the mode used to open each file, EFI_FILE_MODE_READ or + EFI_FILE_MODE_WRITE. + @param FileList Points to the start of a list of files opened. + + @retval EFI_SUCCESS Create the file list successfully. + @return Others Can't create the file list. +**/ +EFI_STATUS +EFIAPI +EfiShellOpenFileList( + IN CHAR16 *Path, + IN UINT64 OpenMode, + IN OUT EFI_SHELL_FILE_INFO **FileList + ) +{ + EFI_STATUS Status; + EFI_SHELL_FILE_INFO *ShellFileListItem; + CHAR16 *Path2; + UINTN Path2Size; + CONST CHAR16 *CurDir; + BOOLEAN Found; + + PathCleanUpDirectories(Path); + + Path2Size = 0; + Path2 = NULL; + + if (FileList == NULL || *FileList == NULL) { + return (EFI_INVALID_PARAMETER); + } + + if (*Path == L'.' && *(Path+1) == L'\\') { + Path+=2; + } + + // + // convert a local path to an absolute path + // + if (StrStr(Path, L":") == NULL) { + CurDir = EfiShellGetCurDir(NULL); + ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL)); + StrnCatGrow(&Path2, &Path2Size, CurDir, 0); + StrnCatGrow(&Path2, &Path2Size, L"\\", 0); + if (*Path == L'\\') { + Path++; + while (PathRemoveLastItem(Path2)) ; + } + ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL)); + StrnCatGrow(&Path2, &Path2Size, Path, 0); + } else { + ASSERT(Path2 == NULL); + StrnCatGrow(&Path2, NULL, Path, 0); + } + + PathCleanUpDirectories (Path2); + + // + // do the search + // + Status = EfiShellFindFiles(Path2, FileList); + + FreePool(Path2); + + if (EFI_ERROR(Status)) { + return (Status); + } + + Found = FALSE; + // + // We had no errors so open all the files (that are not already opened...) + // + for ( ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(*FileList)->Link) + ; !IsNull(&(*FileList)->Link, &ShellFileListItem->Link) + ; ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetNextNode(&(*FileList)->Link, &ShellFileListItem->Link) + ){ + if (ShellFileListItem->Status == 0 && ShellFileListItem->Handle == NULL) { + ShellFileListItem->Status = EfiShellOpenFileByName (ShellFileListItem->FullName, &ShellFileListItem->Handle, OpenMode); + Found = TRUE; + } + } + + if (!Found) { + return (EFI_NOT_FOUND); + } + return(EFI_SUCCESS); +} + +/** + Gets the environment variable and Attributes, or list of environment variables. Can be + used instead of GetEnv(). + + This function returns the current value of the specified environment variable and + the Attributes. If no variable name was specified, then all of the known + variables will be returned. + + @param[in] Name A pointer to the environment variable name. If Name is NULL, + then the function will return all of the defined shell + environment variables. In the case where multiple environment + variables are being returned, each variable will be terminated + by a NULL, and the list will be terminated by a double NULL. + @param[out] Attributes If not NULL, a pointer to the returned attributes bitmask for + the environment variable. In the case where Name is NULL, and + multiple environment variables are being returned, Attributes + is undefined. + + @retval NULL The environment variable doesn't exist. + @return A non-NULL value points to the variable's value. The returned + pointer does not need to be freed by the caller. +**/ +CONST CHAR16 * +EFIAPI +EfiShellGetEnvEx( + IN CONST CHAR16 *Name, + OUT UINT32 *Attributes OPTIONAL + ) +{ + EFI_STATUS Status; + VOID *Buffer; + UINTN Size; + ENV_VAR_LIST *Node; + CHAR16 *CurrentWriteLocation; + + Size = 0; + Buffer = NULL; + + if (Name == NULL) { + + // + // Build the semi-colon delimited list. (2 passes) + // + for ( Node = (ENV_VAR_LIST*)GetFirstNode(&gShellEnvVarList.Link) + ; !IsNull(&gShellEnvVarList.Link, &Node->Link) + ; Node = (ENV_VAR_LIST*)GetNextNode(&gShellEnvVarList.Link, &Node->Link) + ){ + ASSERT(Node->Key != NULL); + Size += StrSize(Node->Key); + } + + Size += 2*sizeof(CHAR16); + + Buffer = AllocateZeroPool(Size); + if (Buffer == NULL) { + return (NULL); + } + CurrentWriteLocation = (CHAR16*)Buffer; + + for ( Node = (ENV_VAR_LIST*)GetFirstNode(&gShellEnvVarList.Link) + ; !IsNull(&gShellEnvVarList.Link, &Node->Link) + ; Node = (ENV_VAR_LIST*)GetNextNode(&gShellEnvVarList.Link, &Node->Link) + ){ + ASSERT(Node->Key != NULL); + StrCpyS( CurrentWriteLocation, + (Size)/sizeof(CHAR16) - (CurrentWriteLocation - ((CHAR16*)Buffer)), + Node->Key + ); + CurrentWriteLocation += StrLen(CurrentWriteLocation) + 1; + } + + } else { + // + // We are doing a specific environment variable + // + Status = ShellFindEnvVarInList(Name, (CHAR16**)&Buffer, &Size, Attributes); + + if (EFI_ERROR(Status)){ + // + // get the size we need for this EnvVariable + // + Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(Name, Attributes, &Size, Buffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + // + // Allocate the space and recall the get function + // + Buffer = AllocateZeroPool(Size); + Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(Name, Attributes, &Size, Buffer); + } + // + // we didn't get it (might not exist) + // free the memory if we allocated any and return NULL + // + if (EFI_ERROR(Status)) { + if (Buffer != NULL) { + FreePool(Buffer); + } + return (NULL); + } else { + // + // If we did not find the environment variable in the gShellEnvVarList + // but get it from UEFI variable storage successfully then we need update + // the gShellEnvVarList. + // + ShellFreeEnvVarList (); + Status = ShellInitEnvVarList (); + ASSERT (Status == EFI_SUCCESS); + } + } + } + + // + // return the buffer + // + return (AddBufferToFreeList(Buffer)); +} + +/** + Gets either a single or list of environment variables. + + If name is not NULL then this function returns the current value of the specified + environment variable. + + If Name is NULL, then a list of all environment variable names is returned. Each is a + NULL terminated string with a double NULL terminating the list. + + @param Name A pointer to the environment variable name. If + Name is NULL, then the function will return all + of the defined shell environment variables. In + the case where multiple environment variables are + being returned, each variable will be terminated by + a NULL, and the list will be terminated by a double + NULL. + + @retval !=NULL A pointer to the returned string. + The returned pointer does not need to be freed by the caller. + + @retval NULL The environment variable doesn't exist or there are + no environment variables. +**/ +CONST CHAR16 * +EFIAPI +EfiShellGetEnv( + IN CONST CHAR16 *Name + ) +{ + return (EfiShellGetEnvEx(Name, NULL)); +} + +/** + Internal variable setting function. Allows for setting of the read only variables. + + @param Name Points to the NULL-terminated environment variable name. + @param Value Points to the NULL-terminated environment variable value. If the value is an + empty string then the environment variable is deleted. + @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE). + + @retval EFI_SUCCESS The environment variable was successfully updated. +**/ +EFI_STATUS +InternalEfiShellSetEnv( + IN CONST CHAR16 *Name, + IN CONST CHAR16 *Value, + IN BOOLEAN Volatile + ) +{ + EFI_STATUS Status; + + if (Value == NULL || StrLen(Value) == 0) { + Status = SHELL_DELETE_ENVIRONMENT_VARIABLE(Name); + if (!EFI_ERROR(Status)) { + ShellRemvoeEnvVarFromList(Name); + } + } else { + SHELL_DELETE_ENVIRONMENT_VARIABLE(Name); + Status = ShellAddEnvVarToList( + Name, Value, StrSize(Value), + EFI_VARIABLE_BOOTSERVICE_ACCESS | (Volatile ? 0 : EFI_VARIABLE_NON_VOLATILE) + ); + if (!EFI_ERROR (Status)) { + Status = Volatile + ? SHELL_SET_ENVIRONMENT_VARIABLE_V (Name, StrSize (Value) - sizeof (CHAR16), Value) + : SHELL_SET_ENVIRONMENT_VARIABLE_NV (Name, StrSize (Value) - sizeof (CHAR16), Value); + if (EFI_ERROR (Status)) { + ShellRemvoeEnvVarFromList(Name); + } + } + } + return Status; +} + +/** + Sets the environment variable. + + This function changes the current value of the specified environment variable. If the + environment variable exists and the Value is an empty string, then the environment + variable is deleted. If the environment variable exists and the Value is not an empty + string, then the value of the environment variable is changed. If the environment + variable does not exist and the Value is an empty string, there is no action. If the + environment variable does not exist and the Value is a non-empty string, then the + environment variable is created and assigned the specified value. + + For a description of volatile and non-volatile environment variables, see UEFI Shell + 2.0 specification section 3.6.1. + + @param Name Points to the NULL-terminated environment variable name. + @param Value Points to the NULL-terminated environment variable value. If the value is an + empty string then the environment variable is deleted. + @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE). + + @retval EFI_SUCCESS The environment variable was successfully updated. +**/ +EFI_STATUS +EFIAPI +EfiShellSetEnv( + IN CONST CHAR16 *Name, + IN CONST CHAR16 *Value, + IN BOOLEAN Volatile + ) +{ + if (Name == NULL || *Name == CHAR_NULL) { + return (EFI_INVALID_PARAMETER); + } + // + // Make sure we dont 'set' a predefined read only variable + // + if ((StrCmp (Name, L"cwd") == 0) || + (StrCmp (Name, L"lasterror") == 0) || + (StrCmp (Name, L"profiles") == 0) || + (StrCmp (Name, L"uefishellsupport") == 0) || + (StrCmp (Name, L"uefishellversion") == 0) || + (StrCmp (Name, L"uefiversion") == 0) || + (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoNest && + StrCmp (Name, mNoNestingEnvVarName) == 0) + ) { + return (EFI_INVALID_PARAMETER); + } + return (InternalEfiShellSetEnv(Name, Value, Volatile)); +} + +/** + Returns the current directory on the specified device. + + If FileSystemMapping is NULL, it returns the current working directory. If the + FileSystemMapping is not NULL, it returns the current directory associated with the + FileSystemMapping. In both cases, the returned name includes the file system + mapping (i.e. fs0:\current-dir). + + Note that the current directory string should exclude the tailing backslash character. + + @param FileSystemMapping A pointer to the file system mapping. If NULL, + then the current working directory is returned. + + @retval !=NULL The current directory. + @retval NULL Current directory does not exist. +**/ +CONST CHAR16 * +EFIAPI +EfiShellGetCurDir( + IN CONST CHAR16 *FileSystemMapping OPTIONAL + ) +{ + CHAR16 *PathToReturn; + UINTN Size; + SHELL_MAP_LIST *MapListItem; + if (!IsListEmpty(&gShellMapList.Link)) { + // + // if parameter is NULL, use current + // + if (FileSystemMapping == NULL) { + return (EfiShellGetEnv(L"cwd")); + } else { + Size = 0; + PathToReturn = NULL; + MapListItem = ShellCommandFindMapItem(FileSystemMapping); + if (MapListItem != NULL) { + ASSERT((PathToReturn == NULL && Size == 0) || (PathToReturn != NULL)); + PathToReturn = StrnCatGrow(&PathToReturn, &Size, MapListItem->MapName, 0); + PathToReturn = StrnCatGrow(&PathToReturn, &Size, MapListItem->CurrentDirectoryPath, 0); + } + } + return (AddBufferToFreeList(PathToReturn)); + } else { + return (NULL); + } +} + +/** + Changes the current directory on the specified device. + + If the FileSystem is NULL, and the directory Dir does not contain a file system's + mapped name, this function changes the current working directory. + + If the FileSystem is NULL and the directory Dir contains a mapped name, then the + current file system and the current directory on that file system are changed. + + If FileSystem is NULL, and Dir is not NULL, then this changes the current working file + system. + + If FileSystem is not NULL and Dir is not NULL, then this function changes the current + directory on the specified file system. + + If the current working directory or the current working file system is changed then the + %cwd% environment variable will be updated + + Note that the current directory string should exclude the tailing backslash character. + + @param FileSystem A pointer to the file system's mapped name. If NULL, then the current working + directory is changed. + @param Dir Points to the NULL-terminated directory on the device specified by FileSystem. + + @retval EFI_SUCCESS The operation was successful + @retval EFI_NOT_FOUND The file system could not be found +**/ +EFI_STATUS +EFIAPI +EfiShellSetCurDir( + IN CONST CHAR16 *FileSystem OPTIONAL, + IN CONST CHAR16 *Dir + ) +{ + CHAR16 *MapName; + SHELL_MAP_LIST *MapListItem; + UINTN Size; + EFI_STATUS Status; + CHAR16 *TempString; + CHAR16 *DirectoryName; + UINTN TempLen; + + Size = 0; + MapName = NULL; + MapListItem = NULL; + TempString = NULL; + DirectoryName = NULL; + + if ((FileSystem == NULL && Dir == NULL) || Dir == NULL) { + return (EFI_INVALID_PARAMETER); + } + + if (IsListEmpty(&gShellMapList.Link)){ + return (EFI_NOT_FOUND); + } + + DirectoryName = StrnCatGrow(&DirectoryName, NULL, Dir, 0); + ASSERT(DirectoryName != NULL); + + PathCleanUpDirectories(DirectoryName); + + if (FileSystem == NULL) { + // + // determine the file system mapping to use + // + if (StrStr(DirectoryName, L":") != NULL) { + ASSERT(MapName == NULL); + MapName = StrnCatGrow(&MapName, NULL, DirectoryName, (StrStr(DirectoryName, L":")-DirectoryName+1)); + } + // + // find the file system mapping's entry in the list + // or use current + // + if (MapName != NULL) { + MapListItem = ShellCommandFindMapItem(MapName); + + // + // make that the current file system mapping + // + if (MapListItem != NULL) { + gShellCurMapping = MapListItem; + } + } else { + MapListItem = gShellCurMapping; + } + + if (MapListItem == NULL) { + FreePool (DirectoryName); + SHELL_FREE_NON_NULL(MapName); + return (EFI_NOT_FOUND); + } + + // + // now update the MapListItem's current directory + // + if (MapListItem->CurrentDirectoryPath != NULL && DirectoryName[StrLen(DirectoryName) - 1] != L':') { + FreePool(MapListItem->CurrentDirectoryPath); + MapListItem->CurrentDirectoryPath = NULL; + } + if (MapName != NULL) { + TempLen = StrLen(MapName); + if (TempLen != StrLen(DirectoryName)) { + ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL)); + MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName+StrLen(MapName), 0); + } + FreePool (MapName); + } else { + ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL)); + MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName, 0); + } + if ((MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] == L'\\') || (MapListItem->CurrentDirectoryPath == NULL)) { + ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL)); + if (MapListItem->CurrentDirectoryPath != NULL) { + MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] = CHAR_NULL; + } + } + } else { + // + // cant have a mapping in the directory... + // + if (StrStr(DirectoryName, L":") != NULL) { + FreePool (DirectoryName); + return (EFI_INVALID_PARAMETER); + } + // + // FileSystem != NULL + // + MapListItem = ShellCommandFindMapItem(FileSystem); + if (MapListItem == NULL) { + FreePool (DirectoryName); + return (EFI_INVALID_PARAMETER); + } +// gShellCurMapping = MapListItem; + if (DirectoryName != NULL) { + // + // change current dir on that file system + // + + if (MapListItem->CurrentDirectoryPath != NULL) { + FreePool(MapListItem->CurrentDirectoryPath); + DEBUG_CODE(MapListItem->CurrentDirectoryPath = NULL;); + } +// ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL)); +// MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, FileSystem, 0); + ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL)); + MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0); + ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL)); + MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName, 0); + if (MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] == L'\\') { + ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL)); + MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] = CHAR_NULL; + } + } + } + FreePool (DirectoryName); + // + // if updated the current directory then update the environment variable + // + if (MapListItem == gShellCurMapping) { + Size = 0; + ASSERT((TempString == NULL && Size == 0) || (TempString != NULL)); + StrnCatGrow(&TempString, &Size, MapListItem->MapName, 0); + ASSERT((TempString == NULL && Size == 0) || (TempString != NULL)); + StrnCatGrow(&TempString, &Size, MapListItem->CurrentDirectoryPath, 0); + Status = InternalEfiShellSetEnv(L"cwd", TempString, TRUE); + FreePool(TempString); + return (Status); + } + return(EFI_SUCCESS); +} + +/** + Return help information about a specific command. + + This function returns the help information for the specified command. The help text + can be internal to the shell or can be from a UEFI Shell manual page. + + If Sections is specified, then each section name listed will be compared in a casesensitive + manner, to the section names described in Appendix B. If the section exists, + it will be appended to the returned help text. If the section does not exist, no + information will be returned. If Sections is NULL, then all help text information + available will be returned. + + @param Command Points to the NULL-terminated UEFI Shell command name. + @param Sections Points to the NULL-terminated comma-delimited + section names to return. If NULL, then all + sections will be returned. + @param HelpText On return, points to a callee-allocated buffer + containing all specified help text. + + @retval EFI_SUCCESS The help text was returned. + @retval EFI_OUT_OF_RESOURCES The necessary buffer could not be allocated to hold the + returned help text. + @retval EFI_INVALID_PARAMETER HelpText is NULL + @retval EFI_NOT_FOUND There is no help text available for Command. +**/ +EFI_STATUS +EFIAPI +EfiShellGetHelpText( + IN CONST CHAR16 *Command, + IN CONST CHAR16 *Sections OPTIONAL, + OUT CHAR16 **HelpText + ) +{ + CONST CHAR16 *ManFileName; + CHAR16 *FixCommand; + EFI_STATUS Status; + + ASSERT(HelpText != NULL); + FixCommand = NULL; + + ManFileName = ShellCommandGetManFileNameHandler(Command); + + if (ManFileName != NULL) { + return (ProcessManFile(ManFileName, Command, Sections, NULL, HelpText)); + } else { + if ((StrLen(Command)> 4) + && (Command[StrLen(Command)-1] == L'i' || Command[StrLen(Command)-1] == L'I') + && (Command[StrLen(Command)-2] == L'f' || Command[StrLen(Command)-2] == L'F') + && (Command[StrLen(Command)-3] == L'e' || Command[StrLen(Command)-3] == L'E') + && (Command[StrLen(Command)-4] == L'.') + ) { + FixCommand = AllocateZeroPool(StrSize(Command) - 4 * sizeof (CHAR16)); + if (FixCommand == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + StrnCpyS( FixCommand, + (StrSize(Command) - 4 * sizeof (CHAR16))/sizeof(CHAR16), + Command, + StrLen(Command)-4 + ); + Status = ProcessManFile(FixCommand, FixCommand, Sections, NULL, HelpText); + FreePool(FixCommand); + return Status; + } else { + return (ProcessManFile(Command, Command, Sections, NULL, HelpText)); + } + } +} + +/** + Gets the enable status of the page break output mode. + + User can use this function to determine current page break mode. + + @retval TRUE The page break output mode is enabled. + @retval FALSE The page break output mode is disabled. +**/ +BOOLEAN +EFIAPI +EfiShellGetPageBreak( + VOID + ) +{ + return(ShellInfoObject.PageBreakEnabled); +} + +/** + Judges whether the active shell is the root shell. + + This function makes the user to know that whether the active Shell is the root shell. + + @retval TRUE The active Shell is the root Shell. + @retval FALSE The active Shell is NOT the root Shell. +**/ +BOOLEAN +EFIAPI +EfiShellIsRootShell( + VOID + ) +{ + return(ShellInfoObject.RootShellInstance); +} + +/** + function to return a semi-colon delimited list of all alias' in the current shell + + up to caller to free the memory. + + @retval NULL No alias' were found + @retval NULL An error occurred getting alias' + @return !NULL a list of all alias' +**/ +CHAR16 * +InternalEfiShellGetListAlias( + VOID + ) +{ + + EFI_STATUS Status; + EFI_GUID Guid; + CHAR16 *VariableName; + UINTN NameSize; + UINTN NameBufferSize; + CHAR16 *RetVal; + UINTN RetSize; + + NameBufferSize = INIT_NAME_BUFFER_SIZE; + VariableName = AllocateZeroPool(NameBufferSize); + RetSize = 0; + RetVal = NULL; + + if (VariableName == NULL) { + return (NULL); + } + + VariableName[0] = CHAR_NULL; + + while (TRUE) { + NameSize = NameBufferSize; + Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid); + if (Status == EFI_NOT_FOUND){ + break; + } else if (Status == EFI_BUFFER_TOO_SMALL) { + NameBufferSize = NameSize > NameBufferSize * 2 ? NameSize : NameBufferSize * 2; + SHELL_FREE_NON_NULL(VariableName); + VariableName = AllocateZeroPool(NameBufferSize); + if (VariableName == NULL) { + Status = EFI_OUT_OF_RESOURCES; + SHELL_FREE_NON_NULL(RetVal); + RetVal = NULL; + break; + } + + NameSize = NameBufferSize; + Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid); + } + + if (EFI_ERROR (Status)) { + SHELL_FREE_NON_NULL(RetVal); + RetVal = NULL; + break; + } + + if (CompareGuid(&Guid, &gShellAliasGuid)){ + ASSERT((RetVal == NULL && RetSize == 0) || (RetVal != NULL)); + RetVal = StrnCatGrow(&RetVal, &RetSize, VariableName, 0); + RetVal = StrnCatGrow(&RetVal, &RetSize, L";", 0); + } // compare guid + } // while + SHELL_FREE_NON_NULL(VariableName); + + return (RetVal); +} + +/** + Convert a null-terminated unicode string, in-place, to all lowercase. + Then return it. + + @param Str The null-terminated string to be converted to all lowercase. + + @return The null-terminated string converted into all lowercase. +**/ +CHAR16 * +ToLower ( + CHAR16 *Str + ) +{ + UINTN Index; + + for (Index = 0; Str[Index] != L'\0'; Index++) { + if (Str[Index] >= L'A' && Str[Index] <= L'Z') { + Str[Index] -= (CHAR16)(L'A' - L'a'); + } + } + return Str; +} + +/** + This function returns the command associated with a alias or a list of all + alias'. + + @param[in] Alias Points to the NULL-terminated shell alias. + If this parameter is NULL, then all + aliases will be returned in ReturnedData. + @param[out] Volatile upon return of a single command if TRUE indicates + this is stored in a volatile fashion. FALSE otherwise. + + @return If Alias is not NULL, it will return a pointer to + the NULL-terminated command for that alias. + If Alias is NULL, ReturnedData points to a ';' + delimited list of alias (e.g. + ReturnedData = "dir;del;copy;mfp") that is NULL-terminated. + @retval NULL an error occurred + @retval NULL Alias was not a valid Alias +**/ +CONST CHAR16 * +EFIAPI +EfiShellGetAlias( + IN CONST CHAR16 *Alias, + OUT BOOLEAN *Volatile OPTIONAL + ) +{ + CHAR16 *RetVal; + UINTN RetSize; + UINT32 Attribs; + EFI_STATUS Status; + CHAR16 *AliasLower; + CHAR16 *AliasVal; + + // Convert to lowercase to make aliases case-insensitive + if (Alias != NULL) { + AliasLower = AllocateCopyPool (StrSize (Alias), Alias); + if (AliasLower == NULL) { + return NULL; + } + ToLower (AliasLower); + + if (Volatile == NULL) { + GetVariable2 (AliasLower, &gShellAliasGuid, (VOID **)&AliasVal, NULL); + FreePool(AliasLower); + return (AddBufferToFreeList(AliasVal)); + } + RetSize = 0; + RetVal = NULL; + Status = gRT->GetVariable(AliasLower, &gShellAliasGuid, &Attribs, &RetSize, RetVal); + if (Status == EFI_BUFFER_TOO_SMALL) { + RetVal = AllocateZeroPool(RetSize); + Status = gRT->GetVariable(AliasLower, &gShellAliasGuid, &Attribs, &RetSize, RetVal); + } + if (EFI_ERROR(Status)) { + if (RetVal != NULL) { + FreePool(RetVal); + } + FreePool(AliasLower); + return (NULL); + } + if ((EFI_VARIABLE_NON_VOLATILE & Attribs) == EFI_VARIABLE_NON_VOLATILE) { + *Volatile = FALSE; + } else { + *Volatile = TRUE; + } + + FreePool (AliasLower); + return (AddBufferToFreeList(RetVal)); + } + return (AddBufferToFreeList(InternalEfiShellGetListAlias())); +} + +/** + Changes a shell command alias. + + This function creates an alias for a shell command or if Alias is NULL it will delete an existing alias. + + this function does not check for built in alias'. + + @param[in] Command Points to the NULL-terminated shell command or existing alias. + @param[in] Alias Points to the NULL-terminated alias for the shell command. If this is NULL, and + Command refers to an alias, that alias will be deleted. + @param[in] Volatile if TRUE the Alias being set will be stored in a volatile fashion. if FALSE the + Alias being set will be stored in a non-volatile fashion. + + @retval EFI_SUCCESS Alias created or deleted successfully. + @retval EFI_NOT_FOUND the Alias intended to be deleted was not found +**/ +EFI_STATUS +InternalSetAlias( + IN CONST CHAR16 *Command, + IN CONST CHAR16 *Alias, + IN BOOLEAN Volatile + ) +{ + EFI_STATUS Status; + CHAR16 *AliasLower; + BOOLEAN DeleteAlias; + + DeleteAlias = FALSE; + if (Alias == NULL) { + // + // We must be trying to remove one if Alias is NULL + // remove an alias (but passed in COMMAND parameter) + // + Alias = Command; + DeleteAlias = TRUE; + } + ASSERT (Alias != NULL); + + // + // Convert to lowercase to make aliases case-insensitive + // + AliasLower = AllocateCopyPool (StrSize (Alias), Alias); + if (AliasLower == NULL) { + return EFI_OUT_OF_RESOURCES; + } + ToLower (AliasLower); + + if (DeleteAlias) { + Status = gRT->SetVariable (AliasLower, &gShellAliasGuid, 0, 0, NULL); + } else { + Status = gRT->SetVariable ( + AliasLower, &gShellAliasGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | (Volatile ? 0 : EFI_VARIABLE_NON_VOLATILE), + StrSize (Command), (VOID *) Command + ); + } + + FreePool (AliasLower); + + return Status; +} + +/** + Changes a shell command alias. + + This function creates an alias for a shell command or if Alias is NULL it will delete an existing alias. + + + @param[in] Command Points to the NULL-terminated shell command or existing alias. + @param[in] Alias Points to the NULL-terminated alias for the shell command. If this is NULL, and + Command refers to an alias, that alias will be deleted. + @param[in] Replace If TRUE and the alias already exists, then the existing alias will be replaced. If + FALSE and the alias already exists, then the existing alias is unchanged and + EFI_ACCESS_DENIED is returned. + @param[in] Volatile if TRUE the Alias being set will be stored in a volatile fashion. if FALSE the + Alias being set will be stored in a non-volatile fashion. + + @retval EFI_SUCCESS Alias created or deleted successfully. + @retval EFI_NOT_FOUND the Alias intended to be deleted was not found + @retval EFI_ACCESS_DENIED The alias is a built-in alias or already existed and Replace was set to + FALSE. + @retval EFI_INVALID_PARAMETER Command is null or the empty string. +**/ +EFI_STATUS +EFIAPI +EfiShellSetAlias( + IN CONST CHAR16 *Command, + IN CONST CHAR16 *Alias, + IN BOOLEAN Replace, + IN BOOLEAN Volatile + ) +{ + if (ShellCommandIsOnAliasList(Alias==NULL?Command:Alias)) { + // + // cant set over a built in alias + // + return (EFI_ACCESS_DENIED); + } else if (Command == NULL || *Command == CHAR_NULL || StrLen(Command) == 0) { + // + // Command is null or empty + // + return (EFI_INVALID_PARAMETER); + } else if (EfiShellGetAlias(Command, NULL) != NULL && !Replace) { + // + // Alias already exists, Replace not set + // + return (EFI_ACCESS_DENIED); + } else { + return (InternalSetAlias(Command, Alias, Volatile)); + } +} + +// Pure FILE_HANDLE operations are passed to FileHandleLib +// these functions are indicated by the * +EFI_SHELL_PROTOCOL mShellProtocol = { + EfiShellExecute, + EfiShellGetEnv, + EfiShellSetEnv, + EfiShellGetAlias, + EfiShellSetAlias, + EfiShellGetHelpText, + EfiShellGetDevicePathFromMap, + EfiShellGetMapFromDevicePath, + EfiShellGetDevicePathFromFilePath, + EfiShellGetFilePathFromDevicePath, + EfiShellSetMap, + EfiShellGetCurDir, + EfiShellSetCurDir, + EfiShellOpenFileList, + EfiShellFreeFileList, + EfiShellRemoveDupInFileList, + EfiShellBatchIsActive, + EfiShellIsRootShell, + EfiShellEnablePageBreak, + EfiShellDisablePageBreak, + EfiShellGetPageBreak, + EfiShellGetDeviceName, + (EFI_SHELL_GET_FILE_INFO)FileHandleGetInfo, //* + (EFI_SHELL_SET_FILE_INFO)FileHandleSetInfo, //* + EfiShellOpenFileByName, + EfiShellClose, + EfiShellCreateFile, + (EFI_SHELL_READ_FILE)FileHandleRead, //* + (EFI_SHELL_WRITE_FILE)FileHandleWrite, //* + (EFI_SHELL_DELETE_FILE)FileHandleDelete, //* + EfiShellDeleteFileByName, + (EFI_SHELL_GET_FILE_POSITION)FileHandleGetPosition, //* + (EFI_SHELL_SET_FILE_POSITION)FileHandleSetPosition, //* + (EFI_SHELL_FLUSH_FILE)FileHandleFlush, //* + EfiShellFindFiles, + EfiShellFindFilesInDir, + (EFI_SHELL_GET_FILE_SIZE)FileHandleGetSize, //* + EfiShellOpenRoot, + EfiShellOpenRootByHandle, + NULL, + SHELL_MAJOR_VERSION, + SHELL_MINOR_VERSION, + + // New for UEFI Shell 2.1 + EfiShellRegisterGuidName, + EfiShellGetGuidName, + EfiShellGetGuidFromName, + EfiShellGetEnvEx +}; + +/** + Function to create and install on the current handle. + + Will overwrite any existing ShellProtocols in the system to be sure that + the current shell is in control. + + This must be removed via calling CleanUpShellProtocol(). + + @param[in, out] NewShell The pointer to the pointer to the structure + to install. + + @retval EFI_SUCCESS The operation was successful. + @return An error from LocateHandle, CreateEvent, or other core function. +**/ +EFI_STATUS +CreatePopulateInstallShellProtocol ( + IN OUT EFI_SHELL_PROTOCOL **NewShell + ) +{ + EFI_STATUS Status; + UINTN BufferSize; + EFI_HANDLE *Buffer; + UINTN HandleCounter; + SHELL_PROTOCOL_HANDLE_LIST *OldProtocolNode; + EFI_SHELL_PROTOCOL *OldShell; + + if (NewShell == NULL) { + return (EFI_INVALID_PARAMETER); + } + + BufferSize = 0; + Buffer = NULL; + OldProtocolNode = NULL; + InitializeListHead(&ShellInfoObject.OldShellList.Link); + + // + // Initialize EfiShellProtocol object... + // + Status = gBS->CreateEvent(0, + 0, + NULL, + NULL, + &mShellProtocol.ExecutionBreak); + if (EFI_ERROR(Status)) { + return (Status); + } + + // + // Get the size of the buffer we need. + // + Status = gBS->LocateHandle(ByProtocol, + &gEfiShellProtocolGuid, + NULL, + &BufferSize, + Buffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + // + // Allocate and recall with buffer of correct size + // + Buffer = AllocateZeroPool(BufferSize); + if (Buffer == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + Status = gBS->LocateHandle(ByProtocol, + &gEfiShellProtocolGuid, + NULL, + &BufferSize, + Buffer); + if (EFI_ERROR(Status)) { + FreePool(Buffer); + return (Status); + } + // + // now overwrite each of them, but save the info to restore when we end. + // + for (HandleCounter = 0 ; HandleCounter < (BufferSize/sizeof(EFI_HANDLE)) ; HandleCounter++) { + Status = gBS->OpenProtocol(Buffer[HandleCounter], + &gEfiShellProtocolGuid, + (VOID **) &OldShell, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR(Status)) { + OldProtocolNode = AllocateZeroPool(sizeof(SHELL_PROTOCOL_HANDLE_LIST)); + if (OldProtocolNode == NULL) { + if (!IsListEmpty (&ShellInfoObject.OldShellList.Link)) { + CleanUpShellProtocol (&mShellProtocol); + } + Status = EFI_OUT_OF_RESOURCES; + break; + } + // + // reinstall over the old one... + // + OldProtocolNode->Handle = Buffer[HandleCounter]; + OldProtocolNode->Interface = OldShell; + Status = gBS->ReinstallProtocolInterface( + OldProtocolNode->Handle, + &gEfiShellProtocolGuid, + OldProtocolNode->Interface, + (VOID*)(&mShellProtocol)); + if (!EFI_ERROR(Status)) { + // + // we reinstalled successfully. log this so we can reverse it later. + // + + // + // add to the list for subsequent... + // + InsertTailList(&ShellInfoObject.OldShellList.Link, &OldProtocolNode->Link); + } + } + } + FreePool(Buffer); + } else if (Status == EFI_NOT_FOUND) { + ASSERT(IsListEmpty(&ShellInfoObject.OldShellList.Link)); + // + // no one else published yet. just publish it ourselves. + // + Status = gBS->InstallProtocolInterface ( + &gImageHandle, + &gEfiShellProtocolGuid, + EFI_NATIVE_INTERFACE, + (VOID*)(&mShellProtocol)); + } + + if (PcdGetBool(PcdShellSupportOldProtocols)){ + ///@todo support ShellEnvironment2 + ///@todo do we need to support ShellEnvironment (not ShellEnvironment2) also? + } + + if (!EFI_ERROR(Status)) { + *NewShell = &mShellProtocol; + } + return (Status); +} + +/** + Opposite of CreatePopulateInstallShellProtocol. + + Free all memory and restore the system to the state it was in before calling + CreatePopulateInstallShellProtocol. + + @param[in, out] NewShell The pointer to the new shell protocol structure. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +CleanUpShellProtocol ( + IN OUT EFI_SHELL_PROTOCOL *NewShell + ) +{ + SHELL_PROTOCOL_HANDLE_LIST *Node2; + + // + // if we need to restore old protocols... + // + if (!IsListEmpty(&ShellInfoObject.OldShellList.Link)) { + for (Node2 = (SHELL_PROTOCOL_HANDLE_LIST *) GetFirstNode (&ShellInfoObject.OldShellList.Link) + ; !IsListEmpty (&ShellInfoObject.OldShellList.Link) + ; Node2 = (SHELL_PROTOCOL_HANDLE_LIST *) GetFirstNode (&ShellInfoObject.OldShellList.Link) + ) { + RemoveEntryList (&Node2->Link); + gBS->ReinstallProtocolInterface (Node2->Handle, &gEfiShellProtocolGuid, NewShell, Node2->Interface); + FreePool (Node2); + } + } else { + // + // no need to restore + // + gBS->UninstallProtocolInterface (gImageHandle, &gEfiShellProtocolGuid, NewShell); + } + return EFI_SUCCESS; +} + +/** + Cleanup the shell environment. + + @param[in, out] NewShell The pointer to the new shell protocol structure. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +CleanUpShellEnvironment ( + IN OUT EFI_SHELL_PROTOCOL *NewShell + ) +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx; + + CleanUpShellProtocol (NewShell); + + Status = gBS->CloseEvent(NewShell->ExecutionBreak); + NewShell->ExecutionBreak = NULL; + + Status = gBS->OpenProtocol( + gST->ConsoleInHandle, + &gEfiSimpleTextInputExProtocolGuid, + (VOID**)&SimpleEx, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + if (!EFI_ERROR (Status)) { + Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlCNotifyHandle1); + Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlCNotifyHandle2); + Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlCNotifyHandle3); + Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlCNotifyHandle4); + Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlSNotifyHandle1); + Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlSNotifyHandle2); + Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlSNotifyHandle3); + Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlSNotifyHandle4); + } + return (Status); +} + +/** + Notification function for keystrokes. + + @param[in] KeyData The key that was pressed. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +NotificationFunction( + IN EFI_KEY_DATA *KeyData + ) +{ + if ( ((KeyData->Key.UnicodeChar == L'c') && + (KeyData->KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED) || KeyData->KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED))) || + (KeyData->Key.UnicodeChar == 3) + ){ + if (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak == NULL) { + return (EFI_UNSUPPORTED); + } + return (gBS->SignalEvent(ShellInfoObject.NewEfiShellProtocol->ExecutionBreak)); + } else if ((KeyData->Key.UnicodeChar == L's') && + (KeyData->KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED) || KeyData->KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED)) + ){ + ShellInfoObject.HaltOutput = TRUE; + } + return (EFI_SUCCESS); +} + +/** + Function to start monitoring for CTRL-C using SimpleTextInputEx. This + feature's enabled state was not known when the shell initially launched. + + @retval EFI_SUCCESS The feature is enabled. + @retval EFI_OUT_OF_RESOURCES There is not enough memory available. +**/ +EFI_STATUS +InernalEfiShellStartMonitor( + VOID + ) +{ + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx; + EFI_KEY_DATA KeyData; + EFI_STATUS Status; + + Status = gBS->OpenProtocol( + gST->ConsoleInHandle, + &gEfiSimpleTextInputExProtocolGuid, + (VOID**)&SimpleEx, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_SHELL_NO_IN_EX), + ShellInfoObject.HiiHandle); + return (EFI_SUCCESS); + } + + if (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak == NULL) { + return (EFI_UNSUPPORTED); + } + + KeyData.KeyState.KeyToggleState = 0; + KeyData.Key.ScanCode = 0; + KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED; + KeyData.Key.UnicodeChar = L'c'; + + Status = SimpleEx->RegisterKeyNotify( + SimpleEx, + &KeyData, + NotificationFunction, + &ShellInfoObject.CtrlCNotifyHandle1); + + KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED; + if (!EFI_ERROR(Status)) { + Status = SimpleEx->RegisterKeyNotify( + SimpleEx, + &KeyData, + NotificationFunction, + &ShellInfoObject.CtrlCNotifyHandle2); + } + KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED; + KeyData.Key.UnicodeChar = 3; + if (!EFI_ERROR(Status)) { + Status = SimpleEx->RegisterKeyNotify( + SimpleEx, + &KeyData, + NotificationFunction, + &ShellInfoObject.CtrlCNotifyHandle3); + } + KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED; + if (!EFI_ERROR(Status)) { + Status = SimpleEx->RegisterKeyNotify( + SimpleEx, + &KeyData, + NotificationFunction, + &ShellInfoObject.CtrlCNotifyHandle4); + } + return (Status); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellProtocol.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellProtocol.h new file mode 100644 index 00000000..bbc373bd --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/Shell/ShellProtocol.h @@ -0,0 +1,938 @@ +/** @file + Member functions of EFI_SHELL_PROTOCOL and functions for creation, + manipulation, and initialization of EFI_SHELL_PROTOCOL. + + (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SHELL_PROTOCOL_HEADER_ +#define _SHELL_PROTOCOL_HEADER_ + +#include "Shell.h" + +typedef struct { + LIST_ENTRY Link; + EFI_SHELL_PROTOCOL *Interface; + EFI_HANDLE Handle; +} SHELL_PROTOCOL_HANDLE_LIST; + +// flags values... +#define SHELL_MAP_FLAGS_CONSIST BIT1 + +/** + Function to create and install on the current handle. + + Will overwrite any existing ShellProtocols in the system to be sure that + the current shell is in control. + + This must be removed via calling CleanUpShellProtocol(). + + @param[in, out] NewShell The pointer to the pointer to the structure + to install. + + @retval EFI_SUCCESS The operation was successful. + @return An error from LocateHandle, CreateEvent, or other core function. +**/ +EFI_STATUS +CreatePopulateInstallShellProtocol ( + IN OUT EFI_SHELL_PROTOCOL **NewShell + ); + +/** + Opposite of CreatePopulateInstallShellProtocol. + + Free all memory and restore the system to the state it was in before calling + CreatePopulateInstallShellProtocol. + + @param[in, out] NewShell The pointer to the new shell protocol structure. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +CleanUpShellProtocol ( + IN OUT EFI_SHELL_PROTOCOL *NewShell + ); + +/** + Cleanup the shell environment. + + @param[in, out] NewShell The pointer to the new shell protocol structure. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +CleanUpShellEnvironment ( + IN OUT EFI_SHELL_PROTOCOL *NewShell + ); + +/** + This function creates a mapping for a device path. + + @param DevicePath Points to the device path. If this is NULL and Mapping points to a valid mapping, + then the mapping will be deleted. + @param Mapping Points to the NULL-terminated mapping for the device path. Must end with a ':' + + @retval EFI_SUCCESS Mapping created or deleted successfully. + @retval EFI_NO_MAPPING There is no handle that corresponds exactly to DevicePath. See the + boot service function LocateDevicePath(). + @retval EFI_ACCESS_DENIED The mapping is a built-in alias. + @retval EFI_INVALID_PARAMETER Mapping was NULL + @retval EFI_INVALID_PARAMETER Mapping did not end with a ':' + @retval EFI_INVALID_PARAMETER DevicePath was not pointing at a device that had a SIMPLE_FILE_SYSTEM_PROTOCOL installed. + @retval EFI_NOT_FOUND There was no mapping found to delete + @retval EFI_OUT_OF_RESOURCES Memory allocation failed +**/ +EFI_STATUS +EFIAPI +EfiShellSetMap( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL, + IN CONST CHAR16 *Mapping + ); + +/** + Gets the device path from the mapping. + + This function gets the device path associated with a mapping. + + @param Mapping A pointer to the mapping + + @retval !=NULL Pointer to the device path that corresponds to the + device mapping. The returned pointer does not need + to be freed. + @retval NULL There is no device path associated with the + specified mapping. +**/ +CONST EFI_DEVICE_PATH_PROTOCOL * +EFIAPI +EfiShellGetDevicePathFromMap( + IN CONST CHAR16 *Mapping + ); + +/** + Gets the mapping that most closely matches the device path. + + This function gets the mapping which corresponds to the device path *DevicePath. If + there is no exact match, then the mapping which most closely matches *DevicePath + is returned, and *DevicePath is updated to point to the remaining portion of the + device path. If there is an exact match, the mapping is returned and *DevicePath + points to the end-of-device-path node. + + @param DevicePath On entry, points to a device path pointer. On + exit, updates the pointer to point to the + portion of the device path after the mapping. + + @retval NULL No mapping was found. + @return !=NULL Pointer to NULL-terminated mapping. The buffer + is callee allocated and should be freed by the caller. +**/ +CONST CHAR16 * +EFIAPI +EfiShellGetMapFromDevicePath( + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath + ); + +/** + Converts a device path to a file system-style path. + + This function converts a device path to a file system path by replacing part, or all, of + the device path with the file-system mapping. If there are more than one application + file system mappings, the one that most closely matches Path will be used. + + @param Path The pointer to the device path + + @retval NULL the device path could not be found. + @return all The pointer of the NULL-terminated file path. The path + is callee-allocated and should be freed by the caller. +**/ +CHAR16 * +EFIAPI +EfiShellGetFilePathFromDevicePath( + IN CONST EFI_DEVICE_PATH_PROTOCOL *Path + ); + +/** + Converts a file system style name to a device path. + + This function converts a file system style name to a device path, by replacing any + mapping references to the associated device path. + + @param Path the pointer to the path + + @return all The pointer of the file path. The file path is callee + allocated and should be freed by the caller. +**/ +EFI_DEVICE_PATH_PROTOCOL * +EFIAPI +EfiShellGetDevicePathFromFilePath( + IN CONST CHAR16 *Path + ); + +/** + Gets the name of the device specified by the device handle. + + This function gets the user-readable name of the device specified by the device + handle. If no user-readable name could be generated, then *BestDeviceName will be + NULL and EFI_NOT_FOUND will be returned. + + If EFI_DEVICE_NAME_USE_COMPONENT_NAME is set, then the function will return the + device's name using the EFI_COMPONENT_NAME2_PROTOCOL, if present on + DeviceHandle. + + If EFI_DEVICE_NAME_USE_DEVICE_PATH is set, then the function will return the + device's name using the EFI_DEVICE_PATH_PROTOCOL, if present on DeviceHandle. + If both EFI_DEVICE_NAME_USE_COMPONENT_NAME and + EFI_DEVICE_NAME_USE_DEVICE_PATH are set, then + EFI_DEVICE_NAME_USE_COMPONENT_NAME will have higher priority. + + @param DeviceHandle The handle of the device. + @param Flags Determines the possible sources of component names. + Valid bits are: + EFI_DEVICE_NAME_USE_COMPONENT_NAME + EFI_DEVICE_NAME_USE_DEVICE_PATH + @param Language A pointer to the language specified for the device + name, in the same format as described in the UEFI + specification, Appendix M + @param BestDeviceName On return, points to the callee-allocated NULL- + terminated name of the device. If no device name + could be found, points to NULL. The name must be + freed by the caller... + + @retval EFI_SUCCESS Get the name successfully. + @retval EFI_NOT_FOUND Fail to get the device name. + @retval EFI_INVALID_PARAMETER Flags did not have a valid bit set. + @retval EFI_INVALID_PARAMETER BestDeviceName was NULL + @retval EFI_INVALID_PARAMETER DeviceHandle was NULL +**/ +EFI_STATUS +EFIAPI +EfiShellGetDeviceName( + IN EFI_HANDLE DeviceHandle, + IN EFI_SHELL_DEVICE_NAME_FLAGS Flags, + IN CHAR8 *Language, + OUT CHAR16 **BestDeviceName + ); + +/** + Opens the root directory of a device on a handle + + This function opens the root directory of a device and returns a file handle to it. + + @param DeviceHandle The handle of the device that contains the volume. + @param FileHandle On exit, points to the file handle corresponding to the root directory on the + device. + + @retval EFI_SUCCESS Root opened successfully. + @retval EFI_NOT_FOUND EFI_SIMPLE_FILE_SYSTEM could not be found or the root directory + could not be opened. + @retval EFI_VOLUME_CORRUPTED The data structures in the volume were corrupted. + @retval EFI_DEVICE_ERROR The device had an error +**/ +EFI_STATUS +EFIAPI +EfiShellOpenRootByHandle( + IN EFI_HANDLE DeviceHandle, + OUT SHELL_FILE_HANDLE *FileHandle + ); + +/** + Opens the root directory of a device. + + This function opens the root directory of a device and returns a file handle to it. + + @param DevicePath Points to the device path corresponding to the device where the + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL is installed. + @param FileHandle On exit, points to the file handle corresponding to the root directory on the + device. + + @retval EFI_SUCCESS Root opened successfully. + @retval EFI_NOT_FOUND EFI_SIMPLE_FILE_SYSTEM could not be found or the root directory + could not be opened. + @retval EFI_VOLUME_CORRUPTED The data structures in the volume were corrupted. + @retval EFI_DEVICE_ERROR The device had an error +**/ +EFI_STATUS +EFIAPI +EfiShellOpenRoot( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT SHELL_FILE_HANDLE *FileHandle + ); + +/** + Returns whether any script files are currently being processed. + + @retval TRUE There is at least one script file active. + @retval FALSE No script files are active now. + +**/ +BOOLEAN +EFIAPI +EfiShellBatchIsActive ( + VOID + ); + +/** + Worker function to open a file based on a device path. this will open the root + of the volume and then traverse down to the file itself. + + @param DevicePath2 Device Path of the file + @param FileHandle Pointer to the file upon a successful return + @param OpenMode mode to open file in. + @param Attributes the File Attributes to use when creating a new file + + @retval EFI_SUCCESS the file is open and FileHandle is valid + @retval EFI_UNSUPPORTED the device path contained non-path elements + @retval other an error occurred. +**/ +EFI_STATUS +InternalOpenFileDevicePath( + IN OUT EFI_DEVICE_PATH_PROTOCOL *DevicePath2, + OUT SHELL_FILE_HANDLE *FileHandle, + IN UINT64 OpenMode, + IN UINT64 Attributes OPTIONAL + ); + +/** + Creates a file or directory by name. + + This function creates an empty new file or directory with the specified attributes and + returns the new file's handle. If the file already exists and is read-only, then + EFI_INVALID_PARAMETER will be returned. + + If the file already existed, it is truncated and its attributes updated. If the file is + created successfully, the FileHandle is the file's handle, else, the FileHandle is NULL. + + If the file name begins with >v, then the file handle which is returned refers to the + shell environment variable with the specified name. If the shell environment variable + already exists and is non-volatile then EFI_INVALID_PARAMETER is returned. + + @param FileName Pointer to NULL-terminated file path + @param FileAttribs The new file's attributes. the different attributes are + described in EFI_FILE_PROTOCOL.Open(). + @param FileHandle On return, points to the created file handle or directory's handle + + @retval EFI_SUCCESS The file was opened. FileHandle points to the new file's handle. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + @retval EFI_UNSUPPORTED could not open the file path + @retval EFI_NOT_FOUND the specified file could not be found on the devide, or could not + file the file system on the device. + @retval EFI_NO_MEDIA the device has no medium. + @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no + longer supported. + @retval EFI_DEVICE_ERROR The device reported an error or can't get the file path according + the DirName. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write + when the media is write-protected. + @retval EFI_ACCESS_DENIED The service denied access to the file. + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. + @retval EFI_VOLUME_FULL The volume is full. +**/ +EFI_STATUS +EFIAPI +EfiShellCreateFile( + IN CONST CHAR16 *FileName, + IN UINT64 FileAttribs, + OUT SHELL_FILE_HANDLE *FileHandle + ); + +/** + Opens a file or a directory by file name. + + This function opens the specified file in the specified OpenMode and returns a file + handle. + If the file name begins with >v, then the file handle which is returned refers to the + shell environment variable with the specified name. If the shell environment variable + exists, is non-volatile and the OpenMode indicates EFI_FILE_MODE_WRITE, then + EFI_INVALID_PARAMETER is returned. + + If the file name is >i, then the file handle which is returned refers to the standard + input. If the OpenMode indicates EFI_FILE_MODE_WRITE, then EFI_INVALID_PARAMETER + is returned. + + If the file name is >o, then the file handle which is returned refers to the standard + output. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER + is returned. + + If the file name is >e, then the file handle which is returned refers to the standard + error. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER + is returned. + + If the file name is NUL, then the file handle that is returned refers to the standard NUL + file. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER is + returned. + + If return EFI_SUCCESS, the FileHandle is the opened file's handle, else, the + FileHandle is NULL. + + @param FileName Points to the NULL-terminated UCS-2 encoded file name. + @param FileHandle On return, points to the file handle. + @param OpenMode File open mode. Either EFI_FILE_MODE_READ or + EFI_FILE_MODE_WRITE from section 12.4 of the UEFI + Specification. + @retval EFI_SUCCESS The file was opened. FileHandle has the opened file's handle. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. FileHandle is NULL. + @retval EFI_UNSUPPORTED Could not open the file path. FileHandle is NULL. + @retval EFI_NOT_FOUND The specified file could not be found on the device or the file + system could not be found on the device. FileHandle is NULL. + @retval EFI_NO_MEDIA The device has no medium. FileHandle is NULL. + @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no + longer supported. FileHandle is NULL. + @retval EFI_DEVICE_ERROR The device reported an error or can't get the file path according + the FileName. FileHandle is NULL. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. FileHandle is NULL. + @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write + when the media is write-protected. FileHandle is NULL. + @retval EFI_ACCESS_DENIED The service denied access to the file. FileHandle is NULL. + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. FileHandle + is NULL. + @retval EFI_VOLUME_FULL The volume is full. FileHandle is NULL. +**/ +EFI_STATUS +EFIAPI +EfiShellOpenFileByName( + IN CONST CHAR16 *FileName, + OUT SHELL_FILE_HANDLE *FileHandle, + IN UINT64 OpenMode + ); + +/** + Deletes the file specified by the file name. + + This function deletes a file. + + @param FileName Points to the NULL-terminated file name. + + @retval EFI_SUCCESS The file was closed and deleted, and the handle was closed. + @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted. + @sa EfiShellCreateFile + @sa FileHandleDelete +**/ +EFI_STATUS +EFIAPI +EfiShellDeleteFileByName( + IN CONST CHAR16 *FileName + ); + +/** + Disables the page break output mode. +**/ +VOID +EFIAPI +EfiShellDisablePageBreak ( + VOID + ); + +/** + Enables the page break output mode. +**/ +VOID +EFIAPI +EfiShellEnablePageBreak ( + VOID + ); + +/** + internal worker function to run a command via Device Path + + @param ParentImageHandle A handle of the image that is executing the specified + command line. + @param DevicePath device path of the file to execute + @param CommandLine Points to the NULL-terminated UCS-2 encoded string + containing the command line. If NULL then the command- + line will be empty. + @param Environment Points to a NULL-terminated array of environment + variables with the format 'x=y', where x is the + environment variable name and y is the value. If this + is NULL, then the current shell environment is used. + @param[out] StartImageStatus Returned status from gBS->StartImage. + + @retval EFI_SUCCESS The command executed successfully. The status code + returned by the command is pointed to by StatusCode. + @retval EFI_INVALID_PARAMETER The parameters are invalid. + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_UNSUPPORTED Nested shell invocations are not allowed. +**/ +EFI_STATUS +InternalShellExecuteDevicePath( + IN CONST EFI_HANDLE *ParentImageHandle, + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN CONST CHAR16 *CommandLine OPTIONAL, + IN CONST CHAR16 **Environment OPTIONAL, + OUT EFI_STATUS *StartImageStatus OPTIONAL + ); + +/** + Execute the command line. + + This function creates a nested instance of the shell and executes the specified + command (CommandLine) with the specified environment (Environment). Upon return, + the status code returned by the specified command is placed in StatusCode. + + If Environment is NULL, then the current environment is used and all changes made + by the commands executed will be reflected in the current environment. If the + Environment is non-NULL, then the changes made will be discarded. + + The CommandLine is executed from the current working directory on the current + device. + + @param ParentImageHandle A handle of the image that is executing the specified + command line. + @param CommandLine Points to the NULL-terminated UCS-2 encoded string + containing the command line. If NULL then the command- + line will be empty. + @param Environment Points to a NULL-terminated array of environment + variables with the format 'x=y', where x is the + environment variable name and y is the value. If this + is NULL, then the current shell environment is used. + @param StatusCode Points to the status code returned by the command. + + @retval EFI_SUCCESS The command executed successfully. The status code + returned by the command is pointed to by StatusCode. + @retval EFI_INVALID_PARAMETER The parameters are invalid. + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_UNSUPPORTED Nested shell invocations are not allowed. +**/ +EFI_STATUS +EFIAPI +EfiShellExecute( + IN EFI_HANDLE *ParentImageHandle, + IN CHAR16 *CommandLine OPTIONAL, + IN CHAR16 **Environment OPTIONAL, + OUT EFI_STATUS *StatusCode OPTIONAL + ); + +/** + Utility cleanup function for EFI_SHELL_FILE_INFO objects. + + 1) frees all pointers (non-NULL) + 2) Closes the SHELL_FILE_HANDLE + + @param FileListNode pointer to the list node to free +**/ +VOID +FreeShellFileInfoNode( + IN EFI_SHELL_FILE_INFO *FileListNode + ); + +/** + Frees the file list. + + This function cleans up the file list and any related data structures. It has no + impact on the files themselves. + + @param FileList The file list to free. Type EFI_SHELL_FILE_INFO is + defined in OpenFileList() + + @retval EFI_SUCCESS Free the file list successfully. + @retval EFI_INVALID_PARAMETER FileList was NULL or *FileList was NULL; +**/ +EFI_STATUS +EFIAPI +EfiShellFreeFileList( + IN EFI_SHELL_FILE_INFO **FileList + ); + +/** + Deletes the duplicate file names files in the given file list. + + This function deletes the reduplicate files in the given file list. + + @param FileList A pointer to the first entry in the file list. + + @retval EFI_SUCCESS Always success. + @retval EFI_INVALID_PARAMETER FileList was NULL or *FileList was NULL; +**/ +EFI_STATUS +EFIAPI +EfiShellRemoveDupInFileList( + IN EFI_SHELL_FILE_INFO **FileList + ); + +/** + Allocates and populates a EFI_SHELL_FILE_INFO structure. if any memory operation + failed it will return NULL. + + @param[in] BasePath the Path to prepend onto filename for FullPath + @param[in] Status Status member initial value. + @param[in] FileName FileName member initial value. + @param[in] Handle Handle member initial value. + @param[in] Info Info struct to copy. + +**/ +EFI_SHELL_FILE_INFO * +CreateAndPopulateShellFileInfo( + IN CONST CHAR16 *BasePath, + IN CONST EFI_STATUS Status, + IN CONST CHAR16 *FileName, + IN CONST SHELL_FILE_HANDLE Handle, + IN CONST EFI_FILE_INFO *Info + ); + +/** + Find all files in a specified directory. + + @param FileDirHandle Handle of the directory to search. + @param FileList On return, points to the list of files in the directory + or NULL if there are no files in the directory. + + @retval EFI_SUCCESS File information was returned successfully. + @retval EFI_VOLUME_CORRUPTED The file system structures have been corrupted. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_NO_MEDIA The device media is not present. + @retval EFI_INVALID_PARAMETER The FileDirHandle was not a directory. +**/ +EFI_STATUS +EFIAPI +EfiShellFindFilesInDir( + IN SHELL_FILE_HANDLE FileDirHandle, + OUT EFI_SHELL_FILE_INFO **FileList + ); + +/** + Find files that match a specified pattern. + + This function searches for all files and directories that match the specified + FilePattern. The FilePattern can contain wild-card characters. The resulting file + information is placed in the file list FileList. + + Wildcards are processed + according to the rules specified in UEFI Shell 2.0 spec section 3.7.1. + + The files in the file list are not opened. The OpenMode field is set to 0 and the FileInfo + field is set to NULL. + + if *FileList is not NULL then it must be a pre-existing and properly initialized list. + + @param FilePattern Points to a NULL-terminated shell file path, including wildcards. + @param FileList On return, points to the start of a file list containing the names + of all matching files or else points to NULL if no matching files + were found. only on a EFI_SUCCESS return will; this be non-NULL. + + @retval EFI_SUCCESS Files found. FileList is a valid list. + @retval EFI_NOT_FOUND No files found. + @retval EFI_NO_MEDIA The device has no media + @retval EFI_DEVICE_ERROR The device reported an error + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted +**/ +EFI_STATUS +EFIAPI +EfiShellFindFiles( + IN CONST CHAR16 *FilePattern, + OUT EFI_SHELL_FILE_INFO **FileList + ); + +/** + Opens the files that match the path specified. + + This function opens all of the files specified by Path. Wildcards are processed + according to the rules specified in UEFI Shell 2.0 spec section 3.7.1. Each + matching file has an EFI_SHELL_FILE_INFO structure created in a linked list. + + @param Path A pointer to the path string. + @param OpenMode Specifies the mode used to open each file, EFI_FILE_MODE_READ or + EFI_FILE_MODE_WRITE. + @param FileList Points to the start of a list of files opened. + + @retval EFI_SUCCESS Create the file list successfully. + @return Others Can't create the file list. +**/ +EFI_STATUS +EFIAPI +EfiShellOpenFileList( + IN CHAR16 *Path, + IN UINT64 OpenMode, + IN OUT EFI_SHELL_FILE_INFO **FileList + ); + +/** + Gets the environment variable. + + This function returns the current value of the specified environment variable. + + @param Name A pointer to the environment variable name + + @retval !=NULL The environment variable's value. The returned + pointer does not need to be freed by the caller. + @retval NULL The environment variable doesn't exist. +**/ +CONST CHAR16 * +EFIAPI +EfiShellGetEnv( + IN CONST CHAR16 *Name + ); + +/** + Sets the environment variable. + + This function changes the current value of the specified environment variable. If the + environment variable exists and the Value is an empty string, then the environment + variable is deleted. If the environment variable exists and the Value is not an empty + string, then the value of the environment variable is changed. If the environment + variable does not exist and the Value is an empty string, there is no action. If the + environment variable does not exist and the Value is a non-empty string, then the + environment variable is created and assigned the specified value. + + For a description of volatile and non-volatile environment variables, see UEFI Shell + 2.0 specification section 3.6.1. + + @param Name Points to the NULL-terminated environment variable name. + @param Value Points to the NULL-terminated environment variable value. If the value is an + empty string then the environment variable is deleted. + @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE). + + @retval EFI_SUCCESS The environment variable was successfully updated. +**/ +EFI_STATUS +EFIAPI +EfiShellSetEnv( + IN CONST CHAR16 *Name, + IN CONST CHAR16 *Value, + IN BOOLEAN Volatile + ); + +/** + Returns the current directory on the specified device. + + If FileSystemMapping is NULL, it returns the current working directory. If the + FileSystemMapping is not NULL, it returns the current directory associated with the + FileSystemMapping. In both cases, the returned name includes the file system + mapping (i.e. fs0:\current-dir). + + @param FileSystemMapping A pointer to the file system mapping. If NULL, + then the current working directory is returned. + + @retval !=NULL The current directory. + @retval NULL Current directory does not exist. +**/ +CONST CHAR16 * +EFIAPI +EfiShellGetCurDir( + IN CONST CHAR16 *FileSystemMapping OPTIONAL + ); + +/** + Changes the current directory on the specified device. + + If the FileSystem is NULL, and the directory Dir does not contain a file system's + mapped name, this function changes the current working directory. If FileSystem is + NULL and the directory Dir contains a mapped name, then the current file system and + the current directory on that file system are changed. + + If FileSystem is not NULL, and Dir is NULL, then this changes the current working file + system. + + If FileSystem is not NULL and Dir is not NULL, then this function changes the current + directory on the specified file system. + + If the current working directory or the current working file system is changed then the + %cwd% environment variable will be updated + + @param FileSystem A pointer to the file system's mapped name. If NULL, then the current working + directory is changed. + @param Dir Points to the NULL-terminated directory on the device specified by FileSystem. + + @retval EFI_SUCCESS The operation was successful +**/ +EFI_STATUS +EFIAPI +EfiShellSetCurDir( + IN CONST CHAR16 *FileSystem OPTIONAL, + IN CONST CHAR16 *Dir + ); + +/** + Return help information about a specific command. + + This function returns the help information for the specified command. The help text + can be internal to the shell or can be from a UEFI Shell manual page. + + If Sections is specified, then each section name listed will be compared in a casesensitive + manner, to the section names described in Appendix B. If the section exists, + it will be appended to the returned help text. If the section does not exist, no + information will be returned. If Sections is NULL, then all help text information + available will be returned. + + @param Command Points to the NULL-terminated UEFI Shell command name. + @param Sections Points to the NULL-terminated comma-delimited + section names to return. If NULL, then all + sections will be returned. + @param HelpText On return, points to a callee-allocated buffer + containing all specified help text. + + @retval EFI_SUCCESS The help text was returned. + @retval EFI_OUT_OF_RESOURCES The necessary buffer could not be allocated to hold the + returned help text. + @retval EFI_INVALID_PARAMETER HelpText is NULL + @retval EFI_NOT_FOUND There is no help text available for Command. +**/ +EFI_STATUS +EFIAPI +EfiShellGetHelpText( + IN CONST CHAR16 *Command, + IN CONST CHAR16 *Sections OPTIONAL, + OUT CHAR16 **HelpText + ); + +/** + Gets the enable status of the page break output mode. + + User can use this function to determine current page break mode. + + @retval TRUE The page break output mode is enabled + @retval FALSE The page break output mode is disabled +**/ +BOOLEAN +EFIAPI +EfiShellGetPageBreak( + VOID + ); + +/** + Judges whether the active shell is the root shell. + + This function makes the user to know that whether the active Shell is the root shell. + + @retval TRUE The active Shell is the root Shell. + @retval FALSE The active Shell is NOT the root Shell. +**/ +BOOLEAN +EFIAPI +EfiShellIsRootShell( + VOID + ); + +/** + This function returns the command associated with a alias or a list of all + alias'. + + @param[in] Command Points to the NULL-terminated shell alias. + If this parameter is NULL, then all + aliases will be returned in ReturnedData. + @param[out] Volatile upon return of a single command if TRUE indicates + this is stored in a volatile fashion. FALSE otherwise. + @return If Alias is not NULL, it will return a pointer to + the NULL-terminated command for that alias. + If Alias is NULL, ReturnedData points to a ';' + delimited list of alias (e.g. + ReturnedData = "dir;del;copy;mfp") that is NULL-terminated. + @retval NULL an error occurred + @retval NULL Alias was not a valid Alias +**/ +CONST CHAR16 * +EFIAPI +EfiShellGetAlias( + IN CONST CHAR16 *Command, + OUT BOOLEAN *Volatile OPTIONAL + ); + +/** + Changes a shell command alias. + + This function creates an alias for a shell command or if Alias is NULL it will delete an existing alias. + + this function does not check for built in alias'. + + @param[in] Command Points to the NULL-terminated shell command or existing alias. + @param[in] Alias Points to the NULL-terminated alias for the shell command. If this is NULL, and + Command refers to an alias, that alias will be deleted. + @param[in] Volatile if TRUE the Alias being set will be stored in a volatile fashion. if FALSE the + Alias being set will be stored in a non-volatile fashion. + + @retval EFI_SUCCESS Alias created or deleted successfully. + @retval EFI_NOT_FOUND the Alias intended to be deleted was not found +**/ +EFI_STATUS +InternalSetAlias( + IN CONST CHAR16 *Command, + IN CONST CHAR16 *Alias OPTIONAL, + IN BOOLEAN Volatile + ); + +/** + Changes a shell command alias. + + This function creates an alias for a shell command or if Alias is NULL it will delete an existing alias. + + + @param[in] Command Points to the NULL-terminated shell command or existing alias. + @param[in] Alias Points to the NULL-terminated alias for the shell command. If this is NULL, and + Command refers to an alias, that alias will be deleted. + @param[in] Replace If TRUE and the alias already exists, then the existing alias will be replaced. If + FALSE and the alias already exists, then the existing alias is unchanged and + EFI_ACCESS_DENIED is returned. + @param[in] Volatile if TRUE the Alias being set will be stored in a volatile fashion. if FALSE the + Alias being set will be stored in a non-volatile fashion. + + @retval EFI_SUCCESS Alias created or deleted successfully. + @retval EFI_NOT_FOUND the Alias intended to be deleted was not found + @retval EFI_ACCESS_DENIED The alias is a built-in alias or already existed and Replace was set to + FALSE. +**/ +EFI_STATUS +EFIAPI +EfiShellSetAlias( + IN CONST CHAR16 *Command, + IN CONST CHAR16 *Alias OPTIONAL, + IN BOOLEAN Replace, + IN BOOLEAN Volatile + ); + +/** + Utility cleanup function for EFI_SHELL_FILE_INFO objects. + + 1) frees all pointers (non-NULL) + 2) Closes the SHELL_FILE_HANDLE + + @param FileListNode pointer to the list node to free +**/ +VOID +InternalFreeShellFileInfoNode( + IN EFI_SHELL_FILE_INFO *FileListNode + ); + +/** + Internal variable setting function. Allows for setting of the read only variables. + + @param Name Points to the NULL-terminated environment variable name. + @param Value Points to the NULL-terminated environment variable value. If the value is an + empty string then the environment variable is deleted. + @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE). + + @retval EFI_SUCCESS The environment variable was successfully updated. +**/ +EFI_STATUS +InternalEfiShellSetEnv( + IN CONST CHAR16 *Name, + IN CONST CHAR16 *Value, + IN BOOLEAN Volatile + ); + +/** + Function to start monitoring for CTRL-C using SimpleTextInputEx. This + feature's enabled state was not known when the shell initially launched. + + @retval EFI_SUCCESS The feature is enabled. + @retval EFI_OUT_OF_RESOURCES There is not enough memory available. +**/ +EFI_STATUS +InernalEfiShellStartMonitor( + VOID + ); + +/** + Notification function for keystrokes. + + @param[in] KeyData The key that was pressed. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +NotificationFunction( + IN EFI_KEY_DATA *KeyData + ); +#endif //_SHELL_PROTOCOL_HEADER_ + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellCTestApp/README.txt b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellCTestApp/README.txt new file mode 100644 index 00000000..6a5f463a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellCTestApp/README.txt @@ -0,0 +1,5 @@ +TestArgv.nsh is a very simple shell script to test how the interpreter parses +the parameters. It uses ShellCTestApp.efi to dump the parameters passed from the +interpreter. + +TestArgv.log is the desired output created using "TestArgv.nsh > TestArgv.log". diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellCTestApp/ShellCTestApp.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellCTestApp/ShellCTestApp.c new file mode 100644 index 00000000..48e896c3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellCTestApp/ShellCTestApp.c @@ -0,0 +1,45 @@ +/** @file + This is a test application that demonstrates how to use the C-style entry point + for a shell application. + + Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include + +/** + UEFI application entry point which has an interface similar to a + standard C main function. + + The ShellCEntryLib library instance wrappers the actual UEFI application + entry point and calls this ShellAppMain function. + + @param[in] Argc The number of items in Argv. + @param[in] Argv Array of pointers to strings. + + @retval 0 The application exited normally. + @retval Other An error occurred. + +**/ +INTN +EFIAPI +ShellAppMain ( + IN UINTN Argc, + IN CHAR16 **Argv + ) +{ + UINTN Index; + if (Argc == 1) { + Print (L"Argv[1] = NULL\n"); + } + for (Index = 1; Index < Argc; Index++) { + Print(L"Argv[%d]: \"%s\"\n", Index, Argv[Index]); + } + + return 0; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellCTestApp/ShellCTestApp.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellCTestApp/ShellCTestApp.inf new file mode 100644 index 00000000..de242b24 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellCTestApp/ShellCTestApp.inf @@ -0,0 +1,34 @@ +## @file +# This is the shell application +# +# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = ShellCTestApp + FILE_GUID = 7a6ca3b8-ee1b-489c-b300-24544a7bd418 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = ShellCEntryLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + ShellCTestApp.c + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + +[LibraryClasses] + ShellCEntryLib + UefiLib diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellCTestApp/TestArgv.log b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellCTestApp/TestArgv.log new file mode 100644 index 00000000..e76781ea Binary files /dev/null and b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellCTestApp/TestArgv.log differ diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellCTestApp/TestArgv.nsh b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellCTestApp/TestArgv.nsh new file mode 100644 index 00000000..fca760c3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellCTestApp/TestArgv.nsh @@ -0,0 +1,58 @@ +#/** @file +# This is a very simple shell script to test how the interpreter parses the parameters. +# +# Copyright (c) 2015, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ +echo -on +set Var_EFCF356F_228C_47C2_AD0C_3B5DAC9A8CFA ValueOfGuid +set Sharp_E8528E46_A008_4221_8DE0_D5AB42A9C580 ^# +set Quote_E95DEE8B_E3AA_4155_9ED5_6916394104FC ^" +set Var_ShellCTestApp_EE6E8BC6_71A6_44A5_BED3_D8F901105CDE ShellCTestApp_EE6E8BC6_71A6_44A5_BED3_D8F901105CDE +alias ShellCTestApp_EE6E8BC6_71A6_44A5_BED3_D8F901105CDE ShellCTestApp + +# +# '^' should escape all special characters (including space) +# but has no impact to non-special characters +# +ShellCTestApp ^^ +ShellCTestApp ^# +ShellCTestApp ^%Var_EFCF356F_228C_47C2_AD0C_3B5DAC9A8CFA% +ShellCTestApp ^" +ShellCTestApp ^ 1 +ShellCTestApp ^ +ShellCTestApp ^1 +ShellCTestApp ^^^" +ShellCTestApp ^^^ + +# +# '#' should be processed before %% replacement, and inside '"' +# +ShellCTestApp #%Var_EFCF356F_228C_47C2_AD0C_3B5DAC9A8CFA% +#ShellCTestApp "#" +ShellCTestApp %Sharp_E8528E46_A008_4221_8DE0_D5AB42A9C580% + +# +# '%' should be processed before grouping parameters +# +ShellCTestApp "%Var_EFCF356F_228C_47C2_AD0C_3B5DAC9A8CFA% 2%Quote_E95DEE8B_E3AA_4155_9ED5_6916394104FC% + +# +# alias should be processed after %% replacement +# +%Var_ShellCTestApp_EE6E8BC6_71A6_44A5_BED3_D8F901105CDE% + +# +# '"' should be stripped, space inside '"' should be kept, +# +ShellCTestApp "p 1" +ShellCTestApp "p"1 +ShellCTestApp "p 1"e"x""" + +set -d Var_EFCF356F_228C_47C2_AD0C_3B5DAC9A8CFA +set -d Sharp_E8528E46_A008_4221_8DE0_D5AB42A9C580 +set -d Quote_E95DEE8B_E3AA_4155_9ED5_6916394104FC +set -d Var_ShellCTestApp_EE6E8BC6_71A6_44A5_BED3_D8F901105CDE +alias -d ShellCTestApp_EE6E8BC6_71A6_44A5_BED3_D8F901105CDE +echo -off \ No newline at end of file diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellExecTestApp/SA.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellExecTestApp/SA.c new file mode 100644 index 00000000..0ed27178 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellExecTestApp/SA.c @@ -0,0 +1,32 @@ +/** @file + This is a simple shell application + + Copyright (c) 2008 - 2010, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include + +/** + 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 + ) +{ + Print(L"ShellExecute - Pass"); + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellExecTestApp/SA.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellExecTestApp/SA.inf new file mode 100644 index 00000000..feb91f18 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellExecTestApp/SA.inf @@ -0,0 +1,36 @@ +## @file +# Sample UEFI Application Reference EDKII Module +# +# This is a simple shell application +# +# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = EmptyApplication + FILE_GUID = 8F7D7B1D-0E1C-4c98-B12E-4EC99C4081AC + 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] + SA.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiApplicationEntryPoint + UefiLib + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellSortTestApp/ShellSortTestApp.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellSortTestApp/ShellSortTestApp.c new file mode 100644 index 00000000..177edcc2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellSortTestApp/ShellSortTestApp.c @@ -0,0 +1,77 @@ +/** @file + This is a test application that demonstrates how to use the sorting functions. + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include + +/** + Test comparator. + + @param[in] b1 The first INTN + @param[in] b2 The other INTN + + @retval 0 They are the same. + @retval -1 b1 is less than b2 + @retval 1 b1 is greater then b2 +**/ +INTN +EFIAPI +Test(CONST VOID *b1, CONST VOID *b2) +{ + if (*(INTN*)b1 == *(INTN*)b2) { + return (0); + } + if (*(INTN*)b1 < *(INTN*)b2) { + return(-1); + } + return (1); +} + +/** + UEFI application entry point which has an interface similar to a + standard C main function. + + The ShellCEntryLib library instance wrappers the actual UEFI application + entry point and calls this ShellAppMain function. + + @param Argc Argument count + @param Argv The parsed arguments + + @retval 0 The application exited normally. + @retval Other An error occurred. + +**/ +INTN +EFIAPI +ShellAppMain ( + IN UINTN Argc, + IN CHAR16 **Argv + ) +{ + INTN Array[10]; + + Array[0] = 2; + Array[1] = 3; + Array[2] = 4; + Array[3] = 1; + Array[4] = 5; + Array[5] = 6; + Array[6] = 7; + Array[7] = 8; + Array[8] = 1; + Array[9] = 5; + + Print(L"Array = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\r\n", Array[0],Array[1],Array[2],Array[3],Array[4],Array[5],Array[6],Array[7],Array[8],Array[9]); + PerformQuickSort(Array, 10, sizeof(INTN), Test); + Print(L"POST-SORT\r\n"); + Print(L"Array = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\r\n", Array[0],Array[1],Array[2],Array[3],Array[4],Array[5],Array[6],Array[7],Array[8],Array[9]); + return 0; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellSortTestApp/ShellSortTestApp.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellSortTestApp/ShellSortTestApp.inf new file mode 100644 index 00000000..9b2c1237 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Application/ShellSortTestApp/ShellSortTestApp.inf @@ -0,0 +1,37 @@ +## @file +# This is the shell sorting testing application +# +# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = ShellSortTestApp + FILE_GUID = 079E8E98-AE93-4b9a-8A71-1DC869F23E09 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = ShellCEntryLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + ShellSortTestApp.c + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + ShellCEntryLib + UefiLib + SortLib + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.c new file mode 100644 index 00000000..8ebe5183 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.c @@ -0,0 +1,966 @@ +/** @file + Shell command for Displaying Performance Metrics. + + The Dp command reads performance data and presents it in several + different formats depending upon the needs of the user. Both + Trace and Measured Profiling information is processed and presented. + + Dp uses the "PerformanceLib" to read the measurement records. + The "TimerLib" provides information about the timer, such as frequency, + beginning, and ending counter values. + Measurement records contain identifying information (Handle, Token, Module) + and start and end time values. + Dp uses this information to group records in different ways. It also uses + timer information to calculate elapsed time for each measurement. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved. + (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "Dp.h" +#include "Literals.h" +#include "DpInternal.h" + +#pragma pack(1) + +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Entry; +} RSDT_TABLE; + +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT64 Entry; +} XSDT_TABLE; + +#pragma pack() + +EFI_HII_HANDLE mDpHiiHandle; + +typedef struct { + EFI_HANDLE Handle; + EFI_GUID ModuleGuid; +} HANDLE_GUID_MAP; + +HANDLE_GUID_MAP *mCacheHandleGuidTable; +UINTN mCachePairCount = 0; + +// +/// Module-Global Variables +///@{ +CHAR16 mGaugeString[DP_GAUGE_STRING_LENGTH + 1]; +CHAR16 mUnicodeToken[DXE_PERFORMANCE_STRING_SIZE]; +UINT64 mInterestThreshold; +BOOLEAN mShowId = FALSE; +UINT8 *mBootPerformanceTable; +UINTN mBootPerformanceTableSize; +BOOLEAN mPeiPhase = FALSE; +BOOLEAN mDxePhase = FALSE; + +PERF_SUMMARY_DATA SummaryData = { 0 }; ///< Create the SummaryData structure and init. to ZERO. +MEASUREMENT_RECORD *mMeasurementList = NULL; +UINTN mMeasurementNum = 0; + +/// Items for which to gather cumulative statistics. +PERF_CUM_DATA CumData[] = { + PERF_INIT_CUM_DATA (LOAD_IMAGE_TOK), + PERF_INIT_CUM_DATA (START_IMAGE_TOK), + PERF_INIT_CUM_DATA (DRIVERBINDING_START_TOK), + PERF_INIT_CUM_DATA (DRIVERBINDING_SUPPORT_TOK), + PERF_INIT_CUM_DATA (DRIVERBINDING_STOP_TOK) +}; + +/// Number of items for which we are gathering cumulative statistics. +UINT32 const NumCum = sizeof(CumData) / sizeof(PERF_CUM_DATA); + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-v", TypeFlag}, // -v Verbose Mode + {L"-A", TypeFlag}, // -A All, Cooked + {L"-R", TypeFlag}, // -R RAW All + {L"-s", TypeFlag}, // -s Summary + {L"-x", TypeFlag}, // -x eXclude Cumulative Items + {L"-i", TypeFlag}, // -i Display Identifier + {L"-c", TypeValue}, // -c Display cumulative data. + {L"-n", TypeValue}, // -n # Number of records to display for A and R + {L"-t", TypeValue}, // -t # Threshold of interest + {NULL, TypeMax} + }; + +///@} + +/** + Display the trailing Verbose information. +**/ +VOID +DumpStatistics( void ) +{ + EFI_STRING StringPtr; + EFI_STRING StringPtrUnknown; + StringPtr = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_STATISTICS), NULL); + StringPtrUnknown = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), mDpHiiHandle, + (StringPtr == NULL) ? StringPtrUnknown : StringPtr); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMTRACE), mDpHiiHandle, SummaryData.NumTrace); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMINCOMPLETE), mDpHiiHandle, SummaryData.NumIncomplete); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMPHASES), mDpHiiHandle, SummaryData.NumSummary); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMHANDLES), mDpHiiHandle, SummaryData.NumHandles, SummaryData.NumTrace - SummaryData.NumHandles); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMPEIMS), mDpHiiHandle, SummaryData.NumPEIMs); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMGLOBALS), mDpHiiHandle, SummaryData.NumGlobal); + SHELL_FREE_NON_NULL (StringPtr); + SHELL_FREE_NON_NULL (StringPtrUnknown); +} + +/** + Get Boot performance table form Acpi table. + +**/ +EFI_STATUS +GetBootPerformanceTable ( + ) +{ + FIRMWARE_PERFORMANCE_TABLE *FirmwarePerformanceTable; + + FirmwarePerformanceTable = (FIRMWARE_PERFORMANCE_TABLE *) EfiLocateFirstAcpiTable ( + EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_DATA_TABLE_SIGNATURE + ); + if (FirmwarePerformanceTable == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_GET_ACPI_FPDT_FAIL), mDpHiiHandle); + return EFI_NOT_FOUND; + } + + mBootPerformanceTable = (UINT8*) (UINTN)FirmwarePerformanceTable->BootPointerRecord.BootPerformanceTablePointer; + mBootPerformanceTableSize = ((BOOT_PERFORMANCE_TABLE *) mBootPerformanceTable)->Header.Length; + + return EFI_SUCCESS; +} + +/** + Get Handle form Module Guid. + + @param ModuleGuid Module Guid. + @param Handle The handle to be returned. + +**/ +VOID +GetHandleFormModuleGuid ( + IN EFI_GUID *ModuleGuid, + IN OUT EFI_HANDLE *Handle + ) +{ + UINTN Index; + + if (IsZeroGuid (ModuleGuid)) { + *Handle = NULL; + } + // + // Try to get the Handle from the cached array. + // + for (Index = 0; Index < mCachePairCount; Index++) { + if (CompareGuid (ModuleGuid, &mCacheHandleGuidTable[Index].ModuleGuid)) { + *Handle = mCacheHandleGuidTable[Index].Handle; + break; + } + } + if (Index >= mCachePairCount) { + *Handle = NULL; + } +} + +/** +Cache the GUID and handle mapping pairs. In order to save time for searching. + +**/ +EFI_STATUS +BuildCachedGuidHandleTable ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN HandleCount; + UINTN Index; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + EFI_DRIVER_BINDING_PROTOCOL *DriverBinding; + EFI_GUID *TempGuid; + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFilePath; + + Status = gBS->LocateHandleBuffer (AllHandles, NULL, NULL, &HandleCount, &HandleBuffer); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLES_ERROR), mDpHiiHandle, Status); + return Status; + } + + mCacheHandleGuidTable = AllocateZeroPool (HandleCount * sizeof (HANDLE_GUID_MAP)); + if (mCacheHandleGuidTable == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + for (Index = 0; Index < HandleCount; Index++) { + // + // Try Handle as ImageHandle. + // + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiLoadedImageProtocolGuid, + (VOID**) &LoadedImage + ); + if (EFI_ERROR (Status)) { + // + // Try Handle as Controller Handle + // + Status = gBS->OpenProtocol ( + HandleBuffer[Index], + &gEfiDriverBindingProtocolGuid, + (VOID **) &DriverBinding, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + // + // Get Image protocol from ImageHandle + // + Status = gBS->HandleProtocol ( + DriverBinding->ImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID**) &LoadedImage + ); + } + } + + if (!EFI_ERROR (Status) && LoadedImage != NULL) { + // + // Get Module Guid from DevicePath. + // + if (LoadedImage->FilePath != NULL && + LoadedImage->FilePath->Type == MEDIA_DEVICE_PATH && + LoadedImage->FilePath->SubType == MEDIA_PIWG_FW_FILE_DP + ) { + FvFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LoadedImage->FilePath; + TempGuid = &FvFilePath->FvFileName; + + mCacheHandleGuidTable[mCachePairCount].Handle = HandleBuffer[Index]; + CopyGuid (&mCacheHandleGuidTable[mCachePairCount].ModuleGuid, TempGuid); + mCachePairCount ++; + } + } + } + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + HandleBuffer = NULL; + } + return EFI_SUCCESS; +} + +/** + Get Measurement form Fpdt records. + + @param RecordHeader Pointer to the start record. + @param IsStart Is start record or End record. + @param Measurement Pointer to the measurement which need to be filled. + +**/ +VOID +GetMeasurementInfo ( + IN EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *RecordHeader, + IN BOOLEAN IsStart, + IN OUT MEASUREMENT_RECORD *Measurement + ) +{ + VOID *ModuleGuid; + EFI_HANDLE StartHandle; + + switch (RecordHeader->Type) { + case FPDT_GUID_EVENT_TYPE: + ModuleGuid = &(((FPDT_GUID_EVENT_RECORD *)RecordHeader)->Guid); + Measurement->Identifier = ((UINT32)((FPDT_GUID_EVENT_RECORD *)RecordHeader)->ProgressID); + if (IsStart) { + Measurement->StartTimeStamp = ((FPDT_GUID_EVENT_RECORD *)RecordHeader)->Timestamp; + } else { + Measurement->EndTimeStamp = ((FPDT_GUID_EVENT_RECORD *)RecordHeader)->Timestamp; + } + switch (Measurement->Identifier) { + case MODULE_START_ID: + case MODULE_END_ID: + if (mPeiPhase) { + Measurement->Token = ALit_PEIM; + Measurement->Module = ALit_PEIM; + } else if (mDxePhase) { + Measurement->Token = ALit_START_IMAGE; + Measurement->Module = ALit_START_IMAGE; + } + break; + default: + ASSERT(FALSE); + } + + if (Measurement->Token != NULL && AsciiStrCmp (Measurement->Token, ALit_PEIM) == 0) { + Measurement->Handle = &(((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Guid); + } else { + GetHandleFormModuleGuid(ModuleGuid, &StartHandle); + Measurement->Handle = StartHandle; + // + // When no perf entry to record the PEI and DXE phase, + // For start image, we need detect the PEIM and non PEIM here. + // + if (Measurement->Token == NULL) { + if (StartHandle == NULL && !IsZeroGuid (ModuleGuid)) { + Measurement->Token = ALit_PEIM; + Measurement->Module = ALit_PEIM; + Measurement->Handle = ModuleGuid; + } else { + Measurement->Token = ALit_START_IMAGE; + Measurement->Module = ALit_START_IMAGE; + } + } + } + break; + + case FPDT_DYNAMIC_STRING_EVENT_TYPE: + ModuleGuid = &(((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Guid); + Measurement->Identifier = ((UINT32)((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->ProgressID); + if (IsStart) { + Measurement->StartTimeStamp = ((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Timestamp; + } else { + Measurement->EndTimeStamp = ((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Timestamp; + } + switch (Measurement->Identifier) { + case MODULE_START_ID: + case MODULE_END_ID: + if (mPeiPhase) { + Measurement->Token = ALit_PEIM; + } else if (mDxePhase) { + Measurement->Token = ALit_START_IMAGE; + } + break; + + case MODULE_LOADIMAGE_START_ID: + case MODULE_LOADIMAGE_END_ID: + Measurement->Token = ALit_LOAD_IMAGE; + break; + + case MODULE_DB_START_ID: + case MODULE_DB_END_ID: + Measurement->Token = ALit_DB_START; + break; + + case MODULE_DB_SUPPORT_START_ID: + case MODULE_DB_SUPPORT_END_ID: + Measurement->Token = ALit_DB_SUPPORT; + break; + + case MODULE_DB_STOP_START_ID: + case MODULE_DB_STOP_END_ID: + Measurement->Token = ALit_DB_STOP; + break; + + default: + Measurement->Token = ((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->String; + break; + } + + Measurement->Module = ((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->String; + + if (Measurement->Token != NULL && AsciiStrCmp (Measurement->Token, ALit_PEIM) == 0) { + Measurement->Handle = &(((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Guid); + } else { + GetHandleFormModuleGuid(ModuleGuid, &StartHandle); + Measurement->Handle = StartHandle; + // + // When no perf entry to record the PEI and DXE phase, + // For start image, we need detect the PEIM and non PEIM here. + // + if (Measurement->Token == NULL && (Measurement->Identifier == MODULE_START_ID || Measurement->Identifier == MODULE_END_ID)) { + if (StartHandle == NULL && !IsZeroGuid (ModuleGuid)) { + Measurement->Token = ALit_PEIM; + Measurement->Handle = ModuleGuid; + } else { + Measurement->Token = ALit_START_IMAGE; + } + } + } + break; + + case FPDT_GUID_QWORD_EVENT_TYPE: + ModuleGuid = &(((FPDT_GUID_QWORD_EVENT_RECORD *)RecordHeader)->Guid); + Measurement->Identifier = ((UINT32)((FPDT_GUID_QWORD_EVENT_RECORD *)RecordHeader)->ProgressID); + if (IsStart) { + Measurement->StartTimeStamp = ((FPDT_GUID_QWORD_EVENT_RECORD *)RecordHeader)->Timestamp; + } else { + Measurement->EndTimeStamp = ((FPDT_GUID_QWORD_EVENT_RECORD *)RecordHeader)->Timestamp; + } + switch (Measurement->Identifier) { + case MODULE_DB_START_ID: + Measurement->Token = ALit_DB_START; + Measurement->Module = ALit_DB_START; + break; + + case MODULE_DB_SUPPORT_START_ID: + case MODULE_DB_SUPPORT_END_ID: + Measurement->Token = ALit_DB_SUPPORT; + Measurement->Module = ALit_DB_SUPPORT; + break; + + case MODULE_DB_STOP_START_ID: + case MODULE_DB_STOP_END_ID: + Measurement->Token = ALit_DB_STOP; + Measurement->Module = ALit_DB_STOP; + break; + + case MODULE_LOADIMAGE_START_ID: + case MODULE_LOADIMAGE_END_ID: + Measurement->Token = ALit_LOAD_IMAGE; + Measurement->Module = ALit_LOAD_IMAGE; + break; + + default: + ASSERT(FALSE); + } + GetHandleFormModuleGuid(ModuleGuid, &StartHandle); + Measurement->Handle = StartHandle; + break; + + case FPDT_GUID_QWORD_STRING_EVENT_TYPE: + ModuleGuid = &(((FPDT_GUID_QWORD_STRING_EVENT_RECORD *)RecordHeader)->Guid); + Measurement->Identifier = ((UINT32)((FPDT_GUID_QWORD_STRING_EVENT_RECORD *)RecordHeader)->ProgressID); + if (IsStart) { + Measurement->StartTimeStamp = ((FPDT_GUID_QWORD_STRING_EVENT_RECORD*)RecordHeader)->Timestamp; + } else { + Measurement->EndTimeStamp = ((FPDT_GUID_QWORD_STRING_EVENT_RECORD *)RecordHeader)->Timestamp; + } + // + // Currently only "DB:Start:" end record with FPDT_GUID_QWORD_STRING_EVENT_TYPE. + // + switch (Measurement->Identifier) { + case MODULE_DB_END_ID: + Measurement->Token = ALit_DB_START; + Measurement->Module = ALit_DB_START; + break; + default: + ASSERT(FALSE); + } + GetHandleFormModuleGuid(ModuleGuid, &StartHandle); + Measurement->Handle = StartHandle; + break; + + case FPDT_DUAL_GUID_STRING_EVENT_TYPE: + ModuleGuid = &(((FPDT_DUAL_GUID_STRING_EVENT_RECORD *)RecordHeader)->Guid1); + Measurement->Identifier = ((UINT32)((FPDT_DUAL_GUID_STRING_EVENT_RECORD *)RecordHeader)->ProgressID); + if (IsStart) { + Measurement->StartTimeStamp = ((FPDT_DUAL_GUID_STRING_EVENT_RECORD *)RecordHeader)->Timestamp; + } else { + Measurement->EndTimeStamp = ((FPDT_DUAL_GUID_STRING_EVENT_RECORD *)RecordHeader)->Timestamp; + } + Measurement->Token = ((FPDT_DUAL_GUID_STRING_EVENT_RECORD *)RecordHeader)->String; + Measurement->Module = ((FPDT_DUAL_GUID_STRING_EVENT_RECORD *)RecordHeader)->String; + GetHandleFormModuleGuid(ModuleGuid, &StartHandle); + Measurement->Handle = StartHandle; + break; + + default: + break; + } +} + +/** + Search the start measurement in the mMeasurementList for the end measurement. + + @param EndMeasureMent Measurement for end record. + +**/ +VOID +SearchMeasurement ( + IN MEASUREMENT_RECORD *EndMeasureMent + ) +{ + INTN Index; + + for (Index = mMeasurementNum - 1; Index >= 0; Index--) { + if (AsciiStrCmp (EndMeasureMent->Token, ALit_PEIM) == 0) { + if (mMeasurementList[Index].EndTimeStamp == 0 && EndMeasureMent->Handle!= NULL && mMeasurementList[Index].Handle != NULL&& + CompareGuid(mMeasurementList[Index].Handle, EndMeasureMent->Handle) && + (AsciiStrCmp (mMeasurementList[Index].Token, EndMeasureMent->Token) == 0) && + (AsciiStrCmp (mMeasurementList[Index].Module, EndMeasureMent->Module) == 0)) { + mMeasurementList[Index].EndTimeStamp = EndMeasureMent->EndTimeStamp; + break; + } + } else if (EndMeasureMent->Identifier == PERF_CROSSMODULE_END_ID) { + if (mMeasurementList[Index].EndTimeStamp == 0 && + (AsciiStrCmp (mMeasurementList[Index].Token, EndMeasureMent->Token) == 0) && + (AsciiStrCmp (mMeasurementList[Index].Module, EndMeasureMent->Module) == 0) && + mMeasurementList[Index].Identifier == PERF_CROSSMODULE_START_ID) { + mMeasurementList[Index].EndTimeStamp = EndMeasureMent->EndTimeStamp; + break; + } + } else { + if (mMeasurementList[Index].EndTimeStamp == 0 && mMeasurementList[Index].Handle == EndMeasureMent->Handle && + (AsciiStrCmp (mMeasurementList[Index].Token, EndMeasureMent->Token) == 0) && + (AsciiStrCmp (mMeasurementList[Index].Module, EndMeasureMent->Module) == 0)) { + mMeasurementList[Index].EndTimeStamp = EndMeasureMent->EndTimeStamp; + break; + } + } + } +} + +/** + Generate the measure record array. + +**/ +EFI_STATUS +BuildMeasurementList ( + ) +{ + EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *RecordHeader; + UINT8 *PerformanceTablePtr; + UINT16 StartProgressId; + UINTN TableLength; + UINT8 *StartRecordEvent; + MEASUREMENT_RECORD MeasureMent; + + mMeasurementList = AllocateZeroPool (mBootPerformanceTableSize); + if (mMeasurementList == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + TableLength = sizeof (BOOT_PERFORMANCE_TABLE); + PerformanceTablePtr = (mBootPerformanceTable + TableLength); + + while (TableLength < mBootPerformanceTableSize) { + RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER*) PerformanceTablePtr; + StartRecordEvent = (UINT8 *)RecordHeader; + StartProgressId = ((FPDT_GUID_EVENT_RECORD *)StartRecordEvent)->ProgressID; + + // + // If the record with ProgressId 0, the record doesn't appear in pairs. The timestamp in the record is the EndTimeStamp, its StartTimeStamp is 0. + // If the record is the start record, fill the info to the measurement in the mMeasurementList. + // If the record is the end record, find the related start measurement in the mMeasurementList and fill the EndTimeStamp. + // + if (StartProgressId == 0) { + GetMeasurementInfo (RecordHeader, FALSE, &(mMeasurementList[mMeasurementNum])); + mMeasurementNum ++; + } else if (((StartProgressId >= PERF_EVENTSIGNAL_START_ID && ((StartProgressId & 0x000F) == 0)) || + (StartProgressId < PERF_EVENTSIGNAL_START_ID && ((StartProgressId & 0x0001) != 0)))) { + // + // Since PEIM and StartImage has same Type and ID when PCD PcdEdkiiFpdtStringRecordEnableOnly = FALSE + // So we need to identify these two kinds of record through different phase. + // + if(StartProgressId == PERF_CROSSMODULE_START_ID ){ + if (AsciiStrCmp (((FPDT_DYNAMIC_STRING_EVENT_RECORD *)StartRecordEvent)->String, ALit_PEI) == 0) { + mPeiPhase = TRUE; + } else if (AsciiStrCmp (((FPDT_DYNAMIC_STRING_EVENT_RECORD *)StartRecordEvent)->String, ALit_DXE) == 0) { + mDxePhase = TRUE; + mPeiPhase = FALSE; + } + } + // Get measurement info form the start record to the mMeasurementList. + GetMeasurementInfo (RecordHeader, TRUE, &(mMeasurementList[mMeasurementNum])); + mMeasurementNum ++; + } else { + ZeroMem(&MeasureMent, sizeof(MEASUREMENT_RECORD)); + GetMeasurementInfo (RecordHeader, FALSE, &MeasureMent); + SearchMeasurement (&MeasureMent); + } + TableLength += RecordHeader->Length; + PerformanceTablePtr += RecordHeader->Length; + } + return EFI_SUCCESS; +} + +/** + Initialize the cumulative data. + +**/ +VOID +InitCumulativeData ( + VOID + ) +{ + UINTN Index; + + for (Index = 0; Index < NumCum; ++Index) { + CumData[Index].Count = 0; + CumData[Index].MinDur = PERF_MAXDUR; + CumData[Index].MaxDur = 0; + CumData[Index].Duration = 0; + } +} + +/** + Initialize the Summary data. + +**/ +VOID +InitSummaryData ( + VOID + ) +{ + SummaryData.NumTrace = 0; + SummaryData.NumIncomplete = 0; + SummaryData.NumSummary = 0; + SummaryData.NumHandles = 0; + SummaryData.NumPEIMs = 0; + SummaryData.NumGlobal = 0; +} + +/** + Dump performance data. + + @param[in] ImageHandle The image handle. + @param[in] SystemTable The system table. + + @retval SHELL_SUCCESS Command completed successfully. + @retval SHELL_INVALID_PARAMETER Command usage error. + @retval SHELL_ABORTED The user aborts the operation. + @retval value Unknown error. +**/ +SHELL_STATUS +RunDp ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + LIST_ENTRY *ParamPackage; + CONST CHAR16 *CmdLineArg; + EFI_STATUS Status; + + PERFORMANCE_PROPERTY *PerformanceProperty; + UINTN Number2Display; + + EFI_STRING StringPtr; + BOOLEAN SummaryMode; + BOOLEAN VerboseMode; + BOOLEAN AllMode; + BOOLEAN RawMode; + BOOLEAN ExcludeMode; + BOOLEAN CumulativeMode; + CONST CHAR16 *CustomCumulativeToken; + PERF_CUM_DATA *CustomCumulativeData; + UINTN NameSize; + SHELL_STATUS ShellStatus; + TIMER_INFO TimerInfo; + UINT64 Intermediate; + + StringPtr = NULL; + SummaryMode = FALSE; + VerboseMode = FALSE; + AllMode = FALSE; + RawMode = FALSE; + ExcludeMode = FALSE; + CumulativeMode = FALSE; + CustomCumulativeData = NULL; + ShellStatus = SHELL_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // Process Command Line arguments + // + Status = ShellCommandLineParse (ParamList, &ParamPackage, NULL, TRUE); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_INVALID_ARG), mDpHiiHandle); + return SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetCount(ParamPackage) > 1){ + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_TOO_MANY), mDpHiiHandle); + return SHELL_INVALID_PARAMETER; + } + + // + // Boolean options + // + VerboseMode = ShellCommandLineGetFlag (ParamPackage, L"-v"); + SummaryMode = (BOOLEAN) (ShellCommandLineGetFlag (ParamPackage, L"-S") || ShellCommandLineGetFlag (ParamPackage, L"-s")); + AllMode = ShellCommandLineGetFlag (ParamPackage, L"-A"); + RawMode = ShellCommandLineGetFlag (ParamPackage, L"-R"); + ExcludeMode = ShellCommandLineGetFlag (ParamPackage, L"-x"); + mShowId = ShellCommandLineGetFlag (ParamPackage, L"-i"); + CumulativeMode = ShellCommandLineGetFlag (ParamPackage, L"-c"); + + if (AllMode && RawMode) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_CONFLICT_ARG), mDpHiiHandle, L"-A", L"-R"); + return SHELL_INVALID_PARAMETER; + } + + // Options with Values + if (ShellCommandLineGetFlag (ParamPackage, L"-n")) { + CmdLineArg = ShellCommandLineGetValue (ParamPackage, L"-n"); + if (CmdLineArg == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_TOO_FEW), mDpHiiHandle); + return SHELL_INVALID_PARAMETER; + } else { + if (!(RawMode || AllMode)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_NO_RAW_ALL), mDpHiiHandle); + return SHELL_INVALID_PARAMETER; + } + Status = ShellConvertStringToUint64(CmdLineArg, &Intermediate, FALSE, TRUE); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_INVALID_NUM_ARG), mDpHiiHandle, L"-n"); + return SHELL_INVALID_PARAMETER; + } else { + Number2Display = (UINTN)Intermediate; + if (Number2Display == 0 || Number2Display > MAXIMUM_DISPLAYCOUNT) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_INVALID_RANGE), mDpHiiHandle, L"-n", 0, MAXIMUM_DISPLAYCOUNT); + return SHELL_INVALID_PARAMETER; + } + } + } + } else { + Number2Display = DEFAULT_DISPLAYCOUNT; + } + + if (ShellCommandLineGetFlag (ParamPackage, L"-t")) { + CmdLineArg = ShellCommandLineGetValue (ParamPackage, L"-t"); + if (CmdLineArg == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_TOO_FEW), mDpHiiHandle); + return SHELL_INVALID_PARAMETER; + } else { + Status = ShellConvertStringToUint64(CmdLineArg, &Intermediate, FALSE, TRUE); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_INVALID_NUM_ARG), mDpHiiHandle, L"-t"); + return SHELL_INVALID_PARAMETER; + } else { + mInterestThreshold = Intermediate; + } + } + } else { + mInterestThreshold = DEFAULT_THRESHOLD; // 1ms := 1,000 us + } + + if (ShellCommandLineGetFlag (ParamPackage, L"-c")) { + CustomCumulativeToken = ShellCommandLineGetValue (ParamPackage, L"-c"); + if (CustomCumulativeToken == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_TOO_FEW), mDpHiiHandle); + return SHELL_INVALID_PARAMETER; + } else { + CustomCumulativeData = AllocateZeroPool (sizeof (PERF_CUM_DATA)); + if (CustomCumulativeData == NULL) { + ShellStatus = SHELL_OUT_OF_RESOURCES; + goto Done; + } + CustomCumulativeData->MinDur = PERF_MAXDUR; + CustomCumulativeData->MaxDur = 0; + CustomCumulativeData->Count = 0; + CustomCumulativeData->Duration = 0; + NameSize = StrLen (CustomCumulativeToken) + 1; + CustomCumulativeData->Name = AllocateZeroPool (NameSize); + if (CustomCumulativeData->Name == NULL) { + ShellStatus = SHELL_OUT_OF_RESOURCES; + goto Done; + } + UnicodeStrToAsciiStrS (CustomCumulativeToken, CustomCumulativeData->Name, NameSize); + } + } + + // + // DP dump performance data by parsing FPDT table in ACPI table. + // Folloing 3 steps are to get the measurement form the FPDT table. + // + + // + //1. Get FPDT from ACPI table. + // + Status = GetBootPerformanceTable (); + if (EFI_ERROR (Status)) { + ShellStatus = Status; + goto Done; + } + + // + //2. Cache the ModuleGuid and hanlde mapping table. + // + Status = BuildCachedGuidHandleTable(); + if (EFI_ERROR (Status)) { + ShellStatus = Status; + goto Done; + } + + // + //3. Build the measurement array form the FPDT records. + // + Status = BuildMeasurementList (); + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_OUT_OF_RESOURCES; + goto Done; + } + + // + // Initialize the pre-defined cumulative data. + // + InitCumulativeData (); + + // + // Initialize the Summary data. + // + InitSummaryData (); + + // + // Timer specific processing + // + // Get the Performance counter characteristics: + // Freq = Frequency in Hz + // StartCount = Value loaded into the counter when it starts counting + // EndCount = Value counter counts to before it needs to be reset + // + Status = EfiGetSystemConfigurationTable (&gPerformanceProtocolGuid, (VOID **) &PerformanceProperty); + if (EFI_ERROR (Status) || (PerformanceProperty == NULL)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PERF_PROPERTY_NOT_FOUND), mDpHiiHandle); + goto Done; + } + + TimerInfo.Frequency = (UINT32)DivU64x32 (PerformanceProperty->Frequency, 1000); + TimerInfo.StartCount = 0; + TimerInfo.EndCount = 0xFFFF; + TimerInfo.CountUp = TRUE; + + // + // Print header + // + // print DP's build version + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_BUILD_REVISION), mDpHiiHandle, DP_MAJOR_VERSION, DP_MINOR_VERSION); + + // print performance timer characteristics + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_KHZ), mDpHiiHandle, TimerInfo.Frequency); + + if (VerboseMode && !RawMode) { + StringPtr = HiiGetString (mDpHiiHandle, + (EFI_STRING_ID) (TimerInfo.CountUp ? STRING_TOKEN (STR_DP_UP) : STRING_TOKEN (STR_DP_DOWN)), NULL); + ASSERT (StringPtr != NULL); + // Print Timer count range and direction + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_TIMER_PROPERTIES), mDpHiiHandle, + StringPtr, + TimerInfo.StartCount, + TimerInfo.EndCount + ); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_VERBOSE_THRESHOLD), mDpHiiHandle, mInterestThreshold); + } + +/**************************************************************************** +**** Print Sections based on command line options +**** +**** Option modes have the following priority: +**** v Verbose -- Valid in combination with any other options +**** t Threshold -- Modifies All, Raw, and Cooked output +**** Default is 0 for All and Raw mode +**** Default is DEFAULT_THRESHOLD for "Cooked" mode +**** n Number2Display Used by All and Raw mode. Otherwise ignored. +**** A All -- R and S options are ignored +**** R Raw -- S option is ignored +**** s Summary -- Modifies "Cooked" output only +**** Cooked (Default) +****************************************************************************/ + GatherStatistics (CustomCumulativeData); + if (CumulativeMode) { + ProcessCumulative (CustomCumulativeData); + } else if (AllMode) { + Status = DumpAllTrace( Number2Display, ExcludeMode); + if (Status == EFI_ABORTED) { + ShellStatus = SHELL_ABORTED; + goto Done; + } + } else if (RawMode) { + Status = DumpRawTrace( Number2Display, ExcludeMode); + if (Status == EFI_ABORTED) { + ShellStatus = SHELL_ABORTED; + goto Done; + } + } else { + //------------- Begin Cooked Mode Processing + ProcessPhases (); + if ( ! SummaryMode) { + Status = ProcessHandles ( ExcludeMode); + if (Status == EFI_ABORTED) { + ShellStatus = SHELL_ABORTED; + goto Done; + } + + Status = ProcessPeims (); + if (Status == EFI_ABORTED) { + ShellStatus = SHELL_ABORTED; + goto Done; + } + + Status = ProcessGlobal (); + if (Status == EFI_ABORTED) { + ShellStatus = SHELL_ABORTED; + goto Done; + } + + ProcessCumulative (NULL); + } + } //------------- End of Cooked Mode Processing + if ( VerboseMode || SummaryMode) { + DumpStatistics(); + } + +Done: + if (ParamPackage != NULL) { + ShellCommandLineFreeVarList (ParamPackage); + } + SHELL_FREE_NON_NULL (StringPtr); + if (CustomCumulativeData != NULL) { + SHELL_FREE_NON_NULL (CustomCumulativeData->Name); + } + SHELL_FREE_NON_NULL (CustomCumulativeData); + + SHELL_FREE_NON_NULL (mMeasurementList); + + SHELL_FREE_NON_NULL (mCacheHandleGuidTable); + + mMeasurementNum = 0; + mCachePairCount = 0; + return ShellStatus; +} + + +/** + Retrieve HII package list from ImageHandle and publish to HII database. + + @param ImageHandle The image handle of the process. + + @return HII handle. +**/ +EFI_HII_HANDLE +InitializeHiiPackage ( + EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + EFI_HII_PACKAGE_LIST_HEADER *PackageList; + EFI_HII_HANDLE HiiHandle; + + // + // Retrieve HII package list from ImageHandle + // + Status = gBS->OpenProtocol ( + ImageHandle, + &gEfiHiiPackageListProtocolGuid, + (VOID **)&PackageList, + ImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return NULL; + } + + // + // Publish HII package list to HII Database. + // + Status = gHiiDatabase->NewPackageList ( + gHiiDatabase, + PackageList, + NULL, + &HiiHandle + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return NULL; + } + return HiiHandle; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.h new file mode 100644 index 00000000..ca6bd2f4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.h @@ -0,0 +1,140 @@ +/** @file + Header file for 'dp' command functions. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _DP_H_ +#define _DP_H_ + + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern EFI_HII_HANDLE mDpHiiHandle; + +#define DP_MAJOR_VERSION 2 +#define DP_MINOR_VERSION 5 + +/** + * The value assigned to DP_DEBUG controls which debug output + * is generated. Set it to ZERO to disable. +**/ +#define DP_DEBUG 0 + +#define DEFAULT_THRESHOLD 1000 ///< One millisecond. +#define DEFAULT_DISPLAYCOUNT 50 +#define MAXIMUM_DISPLAYCOUNT 999999 ///< Arbitrary maximum reasonable number. + +#define PERF_MAXDUR 0xFFFFFFFFFFFFFFFFULL + +/// Determine whether 0 <= C < L. If L == 0, return true regardless of C. +#define WITHIN_LIMIT( C, L) ( ((L) == 0) || ((C) < (L)) ) + +/// Structure for storing Timer specific information. +typedef struct { + UINT64 StartCount; ///< Value timer is initialized with. + UINT64 EndCount; ///< Value timer has just before it wraps. + UINT32 Frequency; ///< Timer count frequency in KHz. + BOOLEAN CountUp; ///< TRUE if the counter counts up. +} TIMER_INFO; + +/** Initialize one PERF_CUM_DATA structure instance for token t. + * + * This parameterized macro takes a single argument, t, which is expected + * to resolve to a pointer to an ASCII string literal. This parameter may + * take any one of the following forms: + * - PERF_INIT_CUM_DATA("Token") A string literal + * - PERF_INIT_CUM_DATA(pointer) A pointer -- CHAR8 *pointer; + * - PERF_INIT_CUM_DATA(array) Address of an array -- CHAR8 array[N]; +**/ +#define PERF_INIT_CUM_DATA(t) { 0ULL, PERF_MAXDUR, 0ULL, (t), 0U } + +typedef struct { + UINT64 Duration; ///< Cumulative duration for this item. + UINT64 MinDur; ///< Smallest duration encountered. + UINT64 MaxDur; ///< Largest duration encountered. + CHAR8 *Name; ///< ASCII name of this item. + UINT32 Count; ///< Total number of measurements accumulated. +} PERF_CUM_DATA; + +typedef struct { + UINT32 NumTrace; ///< Number of recorded TRACE performance measurements. + UINT32 NumIncomplete; ///< Number of measurements with no END value. + UINT32 NumSummary; ///< Number of summary section measurements. + UINT32 NumHandles; ///< Number of measurements with handles. + UINT32 NumPEIMs; ///< Number of measurements of PEIMs. + UINT32 NumGlobal; ///< Number of measurements with END value and NULL handle. +} PERF_SUMMARY_DATA; + +typedef struct { + CONST VOID *Handle; + CONST CHAR8 *Token; ///< Measured token string name. + CONST CHAR8 *Module; ///< Module string name. + UINT64 StartTimeStamp; ///< Start time point. + UINT64 EndTimeStamp; ///< End time point. + UINT32 Identifier; ///< Identifier. +} MEASUREMENT_RECORD; + +typedef struct { + CHAR8 *Name; ///< Measured token string name. + UINT64 CumulativeTime; ///< Accumulated Elapsed Time. + UINT64 MinTime; ///< Minimum Elapsed Time. + UINT64 MaxTime; ///< Maximum Elapsed Time. + UINT32 Count; ///< Number of measurements accumulated. +} PROFILE_RECORD; + +/** + Dump performance data. + + @param[in] ImageHandle The image handle. + @param[in] SystemTable The system table. + + @retval SHELL_SUCCESS Command completed successfully. + @retval SHELL_INVALID_PARAMETER Command usage error. + @retval SHELL_ABORTED The user aborts the operation. + @retval value Unknown error. +**/ +SHELL_STATUS +RunDp ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Retrieve HII package list from ImageHandle and publish to HII database. + + @param ImageHandle The image handle of the process. + + @return HII handle. +**/ +EFI_HII_HANDLE +InitializeHiiPackage ( + EFI_HANDLE ImageHandle + ); +#endif // _DP_H_ diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.uni b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.uni new file mode 100644 index 00000000..8d870057 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.uni @@ -0,0 +1,128 @@ +// *++ +// +// (C) Copyright 2014-2015 Hewlett-Packard Development Company, L.P.
+// Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+// (C) Copyright 2015 Hewlett Packard Enterprise Development LP
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// +// Module Name: +// +// DpStrings.uni +// +// Abstract: +// +// String definitions for the Shell dp command +// +// Revision History: +// +// --*/ + +/=# + +#langdef en-US "English" + +#string STR_DP_UP #language en-US "UP" +#string STR_DP_DOWN #language en-US "DOWN" +#string STR_DP_DASHES #language en-US "-------------------------------------------------------------------------------\n" +#string STR_DP_SECTION_HEADER #language en-US "\n==[ %s ]========\n" +#string STR_DP_INVALID_ARG #language en-US "Invalid argument(s)\n" +#string STR_DP_TOO_MANY #language en-US "Too many arguments\n" +#string STR_DP_TOO_FEW #language en-US "Too few arguments\n" +#string STR_DP_INVALID_NUM_ARG #language en-US "Invalid argument(s), the value of %H%s%N must be numbers\n" +#string STR_DP_INVALID_RANGE #language en-US "Invalid argument(s), the value of %H%s%N must be between %H%d%N and %H%d%N\n" +#string STR_DP_CONFLICT_ARG #language en-US "Invalid argument(s), %H%s%N can not be used together with %H%s%N\n" +#string STR_DP_NO_RAW_ALL #language en-US "Invalid argument(s), -n flag must use with -A or -R\n" +#string STR_DP_HANDLES_ERROR #language en-US "Locate all handles error - %r\n" +#string STR_DP_ERROR_NAME #language en-US "Unknown driver name" +#string STR_PERF_PROPERTY_NOT_FOUND #language en-US "Performance property not found\n" +#string STR_DP_BUILD_REVISION #language en-US "\nDP Build Version: %d.%d\n" +#string STR_DP_KHZ #language en-US "System Performance Timer Frequency: %,8d (KHz)\n" +#string STR_DP_TIMER_PROPERTIES #language en-US "System Performance Timer counts %s from 0x%Lx to 0x%Lx\n" +#string STR_DP_VERBOSE_THRESHOLD #language en-US "Measurements less than %,Ld microseconds are not displayed.\n" +#string STR_DP_SECTION_PHASES #language en-US "Major Phases" +#string STR_DP_SEC_PHASE #language en-US " SEC Phase Duration: %L8d (us)\n" +#string STR_DP_PHASE_BDSTO #language en-US " BDS Timeout: %L8d (ms) included in BDS Duration\n" +#string STR_DP_PHASE_DURATION #language en-US "%5a Phase Duration: %L8d (ms)\n" +#string STR_DP_TOTAL_DURATION #language en-US "Total Duration: %L8d (ms)\n" +#string STR_DP_SECTION_DRIVERS #language en-US "Drivers by Handle" +#string STR_DP_HANDLE_SECTION #language en-US "Index: Handle Driver Name Description Time(us)\n" +#string STR_DP_HANDLE_VARS #language en-US "%5d: [%3x] %36s %11s %L8d\n" +#string STR_DP_HANDLE_SECTION2 #language en-US "Index: Handle Driver Name Description Time(us) ID\n" +#string STR_DP_HANDLE_VARS2 #language en-US "%5d: [%3x] %36s %11s %L8d %5d\n" +#string STR_DP_SECTION_PEIMS #language en-US "PEIMs" +#string STR_DP_PEIM_SECTION #language en-US "Index: Instance GUID Token Time(us)\n" +#string STR_DP_PEIM_VARS #language en-US "%5d: %g PEIM %L8d\n" +#string STR_DP_PEIM_SECTION2 #language en-US "Index: Instance GUID Token Time(us) ID\n" +#string STR_DP_PEIM_VARS2 #language en-US "%5d: %g PEIM %L8d %5d\n" +#string STR_DP_SECTION_GENERAL #language en-US "General" +#string STR_DP_GLOBAL_SECTION #language en-US "Index Name Description Time(us)\n" +#string STR_DP_GLOBAL_VARS #language en-US "%5d:%25s %31s %L8d\n" +#string STR_DP_GLOBAL_SECTION2 #language en-US "Index Name Description Time(us) ID\n" +#string STR_DP_GLOBAL_VARS2 #language en-US "%5d:%25s %31s %L8d %5d\n" +#string STR_DP_SECTION_CUMULATIVE #language en-US "Cumulative" +#string STR_DP_CUMULATIVE_SECT_1 #language en-US "(Times in microsec.) Cumulative Average Shortest Longest\n" +#string STR_DP_CUMULATIVE_SECT_2 #language en-US " Name Count Duration Duration Duration Duration\n" +#string STR_DP_CUMULATIVE_STATS #language en-US "%11a %8d %L10d %L10d %L10d %L10d\n" +#string STR_DP_SECTION_STATISTICS #language en-US "Statistics" +#string STR_DP_STATS_NUMTRACE #language en-US "There were %d measurements taken, of which:\n" +#string STR_DP_STATS_NUMINCOMPLETE #language en-US "%,8d are incomplete.\n" +#string STR_DP_STATS_NUMPHASES #language en-US "%,8d are major execution phases.\n" +#string STR_DP_STATS_NUMHANDLES #language en-US "%,8d have non-NULL handles, %d are NULL.\n" +#string STR_DP_STATS_NUMPEIMS #language en-US "%,8d are PEIMs.\n" +#string STR_DP_STATS_NUMGLOBALS #language en-US "%,8d are general measurements.\n" +#string STR_DP_STATS_NUMPROFILE #language en-US "%,8d are profiling records.\n" +#string STR_DP_SECTION_ALL #language en-US "Sequential Trace Records" +#string STR_DP_ALL_HEADR #language en-US "\nIndex Handle Module Token Time(us)\n" +#string STR_DP_ALL_VARS #language en-US "%5d:%3s0x%08p %36s %13s %L8d\n" +#string STR_DP_ALL_DASHES2 #language en-US "-------------------------------------------------------------------------------------\n" +#string STR_DP_ALL_HEADR2 #language en-US "\nIndex Handle Module Token Time(us) ID\n" +#string STR_DP_ALL_VARS2 #language en-US "%5d:%3s0x%08p %36s %13s %L8d %5d\n" +#string STR_DP_SECTION_RAWTRACE #language en-US "RAW Trace" +#string STR_DP_RAW_DASHES #language en-US "---------------------------------------------------------------------------------------------------------------------------\n" +#string STR_DP_RAW_VARS #language en-US "%5d: %16LX %16LX %16LX %31a %31a\n" +#string STR_DP_RAW_HEADR #language en-US "\nIndex Handle Start Count End Count Token Module\n" +#string STR_DP_RAW_DASHES2 #language en-US "---------------------------------------------------------------------------------------------------------------------------------\n" +#string STR_DP_RAW_VARS2 #language en-US "%5d: %16LX %16LX %16LX %31a %31a %5d\n" +#string STR_DP_RAW_HEADR2 #language en-US "\nIndex Handle Start Count End Count Token Module ID\n" +#string STR_DP_INCOMPLETE #language en-US " I " +#string STR_DP_COMPLETE #language en-US " " +#string STR_ALIT_UNKNOWN #language en-US "Unknown" +#string STR_DP_GET_ACPI_FPDT_FAIL #language en-US "Fail to get Firmware Performance Data Table (FPDT) in ACPI Table\n" + +#string STR_GET_HELP_DP #language en-US "" +".TH dp 0 "Display performance metrics"\r\n" +".SH NAME\r\n" +"Displays performance metrics that are stored in memory.\r\n" +".SH SYNOPSIS\r\n" +"DP [-b] [-v] [-x] [-s | -A | -R] [-t value] [-n count] [-c [token]][-i] [-?]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -b - Displays on multiple pages\r\n" +" -v - Displays additional information\r\n" +" -x - Prevents display of individual measurements for cumulative items\r\n" +" -s - Displays summary information only\r\n" +" -A - Displays all measurements in a list\r\n" +" -R - Displays all measurements in raw format\r\n" +" -t VALUE - Sets display threshold to VALUE microseconds\r\n" +" -n COUNT - Limits display to COUNT lines in All and Raw modes\r\n" +" -i - Displays identifier\r\n" +" -c TOKEN - Display pre-defined and custom cumulative data\r\n" +" Pre-defined cumulative token are:\r\n" +" 1. LoadImage:\r\n" +" 2. StartImage:\r\n" +" 3. DB:Start:\r\n" +" 4. DB:Support:\r\n" +" -? - Displays DP help information\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. Displays Performance metrics that are stored in memory.\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_NOT_FOUND The requested option was not found.\r\n" +" SHELL_INVALID_PARAMETER One of the passed in parameters was incorrectly formatted or its value was out of bounds.\r\n" +" SHELL_UNSUPPORTED The action as requested was unsupported.\r\n" +" SHELL_OUT_OF_RESOURCES There was insufficient free space for the request to be completed.\r\n" diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpApp.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpApp.c new file mode 100644 index 00000000..b77d644d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpApp.c @@ -0,0 +1,47 @@ +/** @file + Entrypoint of "dp" shell standalone application. + + Copyright (c) 2017, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "Dp.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_GET_HELP_DP); + +/** + Entry point of Tftp standalone application. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. + + @retval EFI_SUCCESS Tftp command is executed successfully. + @retval EFI_ABORTED HII package was failed to initialize. + @retval others Other errors when executing tftp command. +**/ +EFI_STATUS +EFIAPI +DpAppInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + mDpHiiHandle = InitializeHiiPackage (ImageHandle); + if (mDpHiiHandle == NULL) { + return EFI_ABORTED; + } + + Status = (EFI_STATUS)RunDp (ImageHandle, SystemTable); + HiiRemovePackages (mDpHiiHandle); + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpApp.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpApp.inf new file mode 100644 index 00000000..25d053a3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpApp.inf @@ -0,0 +1,64 @@ +## @file +# Provides Shell 'dp' standalone application. +# +# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved. +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = dp + FILE_GUID = 1831A379-2D48-45BD-9744-D4059D93815D + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = DpAppInitialize +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +[Sources.common] + Dp.uni + Dp.c + Dp.h + Literals.h + Literals.c + DpInternal.h + DpUtilities.c + DpTrace.c + DpApp.c + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + ShellLib + UefiLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + UefiApplicationEntryPoint + SortLib + PrintLib + DevicePathLib + PerformanceLib + DxeServicesLib + PeCoffGetEntryPointLib + +[Guids] + gPerformanceProtocolGuid ## CONSUMES ## SystemTable + +[Protocols] + gEfiLoadedImageProtocolGuid ## CONSUMES + gEfiDriverBindingProtocolGuid ## SOMETIMES_CONSUMES + gEfiComponentName2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiLoadedImageDevicePathProtocolGuid ## SOMETIMES_CONSUMES + gEfiHiiPackageListProtocolGuid ## CONSUMES + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicCommand.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicCommand.c new file mode 100644 index 00000000..ca8dec0a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicCommand.c @@ -0,0 +1,125 @@ +/** @file + Produce "dp" shell dynamic command. + + Copyright (c) 2017, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "Dp.h" +#include + +/** + This is the shell command handler function pointer callback type. This + function handles the command when it is invoked in the shell. + + @param[in] This The instance of the EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL. + @param[in] SystemTable The pointer to the system table. + @param[in] ShellParameters The parameters associated with the command. + @param[in] Shell The instance of the shell protocol used in the context + of processing this command. + + @return EFI_SUCCESS the operation was successful + @return other the operation failed. +**/ +SHELL_STATUS +EFIAPI +DpCommandHandler ( + IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This, + IN EFI_SYSTEM_TABLE *SystemTable, + IN EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters, + IN EFI_SHELL_PROTOCOL *Shell + ) +{ + gEfiShellParametersProtocol = ShellParameters; + gEfiShellProtocol = Shell; + return RunDp (gImageHandle, SystemTable); +} + +/** + This is the command help handler function pointer callback type. This + function is responsible for displaying help information for the associated + command. + + @param[in] This The instance of the EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL. + @param[in] Language The pointer to the language string to use. + + @return string Pool allocated help string, must be freed by caller +**/ +CHAR16 * +EFIAPI +DpCommandGetHelp ( + IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This, + IN CONST CHAR8 *Language + ) +{ + return HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_GET_HELP_DP), Language); +} + +EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL mDpDynamicCommand = { + L"dp", + DpCommandHandler, + DpCommandGetHelp +}; + +/** + Entry point of Tftp Dynamic Command. + + Produce the DynamicCommand protocol to handle "tftp" command. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. + + @retval EFI_SUCCESS Tftp command is executed successfully. + @retval EFI_ABORTED HII package was failed to initialize. + @retval others Other errors when executing tftp command. +**/ +EFI_STATUS +EFIAPI +DpCommandInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + mDpHiiHandle = InitializeHiiPackage (ImageHandle); + if (mDpHiiHandle == NULL) { + return EFI_ABORTED; + } + + Status = gBS->InstallProtocolInterface ( + &ImageHandle, + &gEfiShellDynamicCommandProtocolGuid, + EFI_NATIVE_INTERFACE, + &mDpDynamicCommand + ); + ASSERT_EFI_ERROR (Status); + return Status; +} + +/** + Tftp driver unload handler. + + @param ImageHandle The image handle of the process. + + @retval EFI_SUCCESS The image is unloaded. + @retval Others Failed to unload the image. +**/ +EFI_STATUS +EFIAPI +DpUnload ( + IN EFI_HANDLE ImageHandle +) +{ + EFI_STATUS Status; + Status = gBS->UninstallProtocolInterface ( + ImageHandle, + &gEfiShellDynamicCommandProtocolGuid, + &mDpDynamicCommand + ); + if (EFI_ERROR (Status)) { + return Status; + } + HiiRemovePackages (mDpHiiHandle); + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicCommand.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicCommand.inf new file mode 100644 index 00000000..159632a3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicCommand.inf @@ -0,0 +1,68 @@ +## @file +# Provides Shell 'dp' dynamic command. +# +# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved. +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = dpDynamicCommand + FILE_GUID = 0253F9FA-129A-4A8D-B12E-7DC2B6376302 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = DpCommandInitialize + UNLOAD_IMAGE = DpUnload +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +[Sources.common] + Dp.uni + Dp.c + Dp.h + Literals.h + Literals.c + DpInternal.h + DpUtilities.c + DpTrace.c + DpDynamicCommand.c + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + ShellLib + UefiLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + UefiDriverEntryPoint + SortLib + PrintLib + DevicePathLib + PerformanceLib + DxeServicesLib + PeCoffGetEntryPointLib + +[Guids] + gPerformanceProtocolGuid ## CONSUMES ## SystemTable + +[Protocols] + gEfiLoadedImageProtocolGuid ## CONSUMES + gEfiDriverBindingProtocolGuid ## SOMETIMES_CONSUMES + gEfiComponentName2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiLoadedImageDevicePathProtocolGuid ## SOMETIMES_CONSUMES + gEfiHiiPackageListProtocolGuid ## CONSUMES + gEfiShellDynamicCommandProtocolGuid ## PRODUCES + +[DEPEX] + TRUE diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpInternal.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpInternal.h new file mode 100644 index 00000000..d6d30c54 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpInternal.h @@ -0,0 +1,315 @@ +/** @file + Declarations of objects defined internally to the Dp Application. + + Declarations of data and functions which are private to the Dp application. + This file should never be referenced by anything other than components of the + Dp application. In addition to global data, function declarations for + DpUtilities.c, DpTrace.c, and DpProfile.c are included here. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved. + (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _DP_INTELNAL_H_ +#define _DP_INTELNAL_H_ + +#define DP_GAUGE_STRING_LENGTH 36 + +// +/// Module-Global Variables +///@{ +extern EFI_HII_HANDLE mDpHiiHandle; +extern CHAR16 mGaugeString[DP_GAUGE_STRING_LENGTH + 1]; +extern CHAR16 mUnicodeToken[DXE_PERFORMANCE_STRING_SIZE]; +extern UINT64 mInterestThreshold; +extern BOOLEAN mShowId; +extern UINT8 *mBootPerformanceTable; +extern UINTN mBootPerformanceTableLength; +extern MEASUREMENT_RECORD *mMeasurementList; +extern UINTN mMeasurementNum; + +extern PERF_SUMMARY_DATA SummaryData; ///< Create the SummaryData structure and init. to ZERO. + +/// Items for which to gather cumulative statistics. +extern PERF_CUM_DATA CumData[]; + +/// Number of items for which we are gathering cumulative statistics. +extern UINT32 const NumCum; + +///@} + +/** + Calculate an event's duration in timer ticks. + + Given the count direction and the event's start and end timer values, + calculate the duration of the event in timer ticks. Information for + the current measurement is pointed to by the parameter. + + If the measurement's start time is 1, it indicates that the developer + is indicating that the measurement began at the release of reset. + The start time is adjusted to the timer's starting count before performing + the elapsed time calculation. + + The calculated duration, in ticks, is the absolute difference between + the measurement's ending and starting counts. + + @param Measurement Pointer to a MEASUREMENT_RECORD structure containing + data for the current measurement. + + @return The 64-bit duration of the event. +**/ +UINT64 +GetDuration ( + IN OUT MEASUREMENT_RECORD *Measurement + ); + +/** + Determine whether the Measurement record is for an EFI Phase. + + The Token and Module members of the measurement record are checked. + Module must be empty and Token must be one of SEC, PEI, DXE, BDS, or SHELL. + + @param[in] Measurement A pointer to the Measurement record to test. + + @retval TRUE The measurement record is for an EFI Phase. + @retval FALSE The measurement record is NOT for an EFI Phase. +**/ +BOOLEAN +IsPhase( + IN MEASUREMENT_RECORD *Measurement + ); + +/** + Determine whether the Measurement record is for core code. + + @param[in] Measurement A pointer to the Measurement record to test. + + @retval TRUE The measurement record is used for core. + @retval FALSE The measurement record is NOT used for core. + +**/ +BOOLEAN +IsCorePerf( + IN MEASUREMENT_RECORD *Measurement + ); + +/** + 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 converted + to Unicode and copied into UnicodeBuffer. The name is truncated, + if necessary, to ensure that UnicodeBuffer is not overrun. + + @param[in] PdbFileName Pdb file name. + @param[out] UnicodeBuffer The resultant Unicode File Name. + +**/ +VOID +DpGetShortPdbFileName ( + IN CHAR8 *PdbFileName, + OUT CHAR16 *UnicodeBuffer + ); + +/** + Get a human readable name for an image handle. + The following methods will be tried orderly: + 1. Image PDB + 2. ComponentName2 protocol + 3. FFS UI section + 4. Image GUID + 5. Image DevicePath + 6. Unknown Driver Name + + @param[in] Handle + + @post The resulting Unicode name string is stored in the + mGaugeString global array. + +**/ +VOID +DpGetNameFromHandle ( + IN EFI_HANDLE Handle + ); + +/** + Calculate the Duration in microseconds. + + Duration is multiplied by 1000, instead of Frequency being divided by 1000 or + multiplying the result by 1000, in order to maintain precision. Since Duration is + a 64-bit value, multiplying it by 1000 is unlikely to produce an overflow. + + The time is calculated as (Duration * 1000) / Timer_Frequency. + + @param[in] Duration The event duration in timer ticks. + + @return A 64-bit value which is the Elapsed time in microseconds. +**/ +UINT64 +DurationInMicroSeconds ( + IN UINT64 Duration + ); + +/** + Get index of Measurement Record's match in the CumData array. + + If the Measurement's Token value matches a Token in one of the CumData + records, the index of the matching record is returned. The returned + index is a signed value so that negative values can indicate that + the Measurement didn't match any entry in the CumData array. + + @param[in] Measurement A pointer to a Measurement Record to match against the CumData array. + + @retval <0 Token is not in the CumData array. + @retval >=0 Return value is the index into CumData where Token is found. +**/ +INTN +GetCumulativeItem( + IN MEASUREMENT_RECORD *Measurement + ); + +/** + Collect verbose statistics about the logged performance measurements. + + General Summary information for all Trace measurements is gathered and + stored within the SummaryData structure. This information is both + used internally by subsequent reporting functions, and displayed + at the end of verbose reports. + + @pre The SummaryData and CumData structures must be initialized + prior to calling this function. + + @post The SummaryData and CumData structures contain statistics for the + current performance logs. + + @param[in, out] CustomCumulativeData The pointer to the custom cumulative data. + +**/ +VOID +GatherStatistics( + IN OUT PERF_CUM_DATA *CustomCumulativeData OPTIONAL + ); + +/** + Gather and print ALL Trace Records. + + Displays all "interesting" Trace measurements in order.
+ The number of records displayed is controlled by: + - records with a duration less than mInterestThreshold microseconds are not displayed. + - No more than Limit records are displayed. A Limit of zero will not limit the output. + - If the ExcludeFlag is TRUE, records matching entries in the CumData array are not + displayed. + + @pre The mInterestThreshold global variable is set to the shortest duration to be printed. + The mGaugeString and mUnicodeToken global arrays are used for temporary string storage. + They must not be in use by a calling function. + + @param[in] Limit The number of records to print. Zero is ALL. + @param[in] ExcludeFlag TRUE to exclude individual Cumulative items from display. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_ABORTED The user aborts the operation. + @return Others from a call to gBS->LocateHandleBuffer(). +**/ +EFI_STATUS +DumpAllTrace( + IN UINTN Limit, + IN BOOLEAN ExcludeFlag + ); + +/** + Gather and print Raw Trace Records. + + All Trace measurements with a duration greater than or equal to + mInterestThreshold are printed without interpretation. + + The number of records displayed is controlled by: + - records with a duration less than mInterestThreshold microseconds are not displayed. + - No more than Limit records are displayed. A Limit of zero will not limit the output. + - If the ExcludeFlag is TRUE, records matching entries in the CumData array are not + displayed. + + @pre The mInterestThreshold global variable is set to the shortest duration to be printed. + + @param[in] Limit The number of records to print. Zero is ALL. + @param[in] ExcludeFlag TRUE to exclude individual Cumulative items from display. + @retval EFI_SUCCESS The operation was successful. + @retval EFI_ABORTED The user aborts the operation. +**/ +EFI_STATUS +DumpRawTrace( + IN UINTN Limit, + IN BOOLEAN ExcludeFlag + ); + +/** + Gather and print Major Phase metrics. + +**/ +VOID +ProcessPhases( + VOID + ); + + +/** + Gather and print Handle data. + + @param[in] ExcludeFlag TRUE to exclude individual Cumulative items from display. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_ABORTED The user aborts the operation. + @return Others from a call to gBS->LocateHandleBuffer(). +**/ +EFI_STATUS +ProcessHandles( + IN BOOLEAN ExcludeFlag + ); + + +/** + Gather and print PEIM data. + + Only prints complete PEIM records + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_ABORTED The user aborts the operation. +**/ +EFI_STATUS +ProcessPeims( + VOID + ); + +/** + Gather and print global data. + + Strips out incomplete or "Execution Phase" records + Only prints records where Handle is NULL + Increment TIndex for every record, even skipped ones, so that we have an + indication of every measurement record taken. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_ABORTED The user aborts the operation. +**/ +EFI_STATUS +ProcessGlobal( + VOID + ); + +/** + Gather and print cumulative data. + + Traverse the measurement records and:
+ For each record with a Token listed in the CumData array:
+ - Update the instance count and the total, minimum, and maximum durations. + Finally, print the gathered cumulative statistics. + + @param[in] CustomCumulativeData The pointer to the custom cumulative data. + +**/ +VOID +ProcessCumulative( + IN PERF_CUM_DATA *CustomCumulativeData OPTIONAL + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpTrace.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpTrace.c new file mode 100644 index 00000000..d66f4bd6 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpTrace.c @@ -0,0 +1,904 @@ +/** @file + Trace reporting for the Dp utility. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved. + (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Dp.h" +#include "Literals.h" +#include "DpInternal.h" + +/** + Attempts to retrieve a performance measurement log entry from the performance measurement log. + + + @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve. + 0, then the first performance measurement log entry is retrieved. + On exit, the key of the next performance log entry. + @param Handle Pointer to environment specific context used to identify the component + being measured. + @param Token Pointer to a Null-terminated ASCII string that identifies the component + being measured. + @param Module Pointer to a Null-terminated ASCII string that identifies the module + being measured. + @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement + was started. + @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement + was ended. + @param Identifier Pointer to the 32-bit identifier that was recorded when the measurement + was ended. + + @return The key for the next performance log entry (in general case). + +**/ +UINTN +GetPerformanceMeasurementRecord ( + IN UINTN LogEntryKey, + OUT CONST VOID **Handle, + OUT CONST CHAR8 **Token, + OUT CONST CHAR8 **Module, + OUT UINT64 *StartTimeStamp, + OUT UINT64 *EndTimeStamp, + OUT UINT32 *Identifier + ) +{ + if (LogEntryKey == mMeasurementNum) { + return 0; + } + + *Handle = (VOID *) (UINTN) mMeasurementList[LogEntryKey].Handle; + *Token = mMeasurementList[LogEntryKey].Token; + *Module = mMeasurementList[LogEntryKey].Module; + *StartTimeStamp = mMeasurementList[LogEntryKey].StartTimeStamp; + *EndTimeStamp = mMeasurementList[LogEntryKey].EndTimeStamp; + *Identifier = mMeasurementList[LogEntryKey].Identifier; + + LogEntryKey ++; + + return LogEntryKey; +} + +/** + Collect verbose statistics about the logged performance measurements. + + General Summary information for all Trace measurements is gathered and + stored within the SummaryData structure. This information is both + used internally by subsequent reporting functions, and displayed + at the end of verbose reports. + + @pre The SummaryData and CumData structures must be initialized + prior to calling this function. + + @post The SummaryData and CumData structures contain statistics for the + current performance logs. + + @param[in, out] CustomCumulativeData A pointer to the custom cumulative data. + +**/ +VOID +GatherStatistics( + IN OUT PERF_CUM_DATA *CustomCumulativeData OPTIONAL + ) +{ + MEASUREMENT_RECORD Measurement; + UINT64 Duration; + UINTN LogEntryKey; + INTN TIndex; + + LogEntryKey = 0; + while ((LogEntryKey = GetPerformanceMeasurementRecord ( + LogEntryKey, + &Measurement.Handle, + &Measurement.Token, + &Measurement.Module, + &Measurement.StartTimeStamp, + &Measurement.EndTimeStamp, + &Measurement.Identifier)) != 0) + { + ++SummaryData.NumTrace; // Count the number of TRACE Measurement records + if (Measurement.EndTimeStamp == 0) { + ++SummaryData.NumIncomplete; // Count the incomplete records + continue; + } + + if (Measurement.Handle != NULL) { + ++SummaryData.NumHandles; // Count the number of measurements with non-NULL handles + } + + if (IsPhase( &Measurement)) { + ++SummaryData.NumSummary; // Count the number of major phases + } + else { // !IsPhase + if(Measurement.Handle == NULL) { + ++SummaryData.NumGlobal; + } + } + + if (AsciiStrCmp (Measurement.Token, ALit_PEIM) == 0) { + ++SummaryData.NumPEIMs; // Count PEIM measurements + } + + Duration = GetDuration (&Measurement); + TIndex = GetCumulativeItem (&Measurement); + if (TIndex >= 0) { + CumData[TIndex].Duration += Duration; + CumData[TIndex].Count++; + if ( Duration < CumData[TIndex].MinDur ) { + CumData[TIndex].MinDur = Duration; + } + if ( Duration > CumData[TIndex].MaxDur ) { + CumData[TIndex].MaxDur = Duration; + } + } + + // + // Collect the data for custom cumulative data. + // + if ((CustomCumulativeData != NULL) && (AsciiStrCmp (Measurement.Token, CustomCumulativeData->Name) == 0)) { + CustomCumulativeData->Duration += Duration; + CustomCumulativeData->Count++; + if (Duration < CustomCumulativeData->MinDur) { + CustomCumulativeData->MinDur = Duration; + } + if (Duration > CustomCumulativeData->MaxDur) { + CustomCumulativeData->MaxDur = Duration; + } + } + } +} + +/** + Gather and print ALL Trace Records. + + Displays all "interesting" Trace measurements in order.
+ The number of records displayed is controlled by: + - records with a duration less than mInterestThreshold microseconds are not displayed. + - No more than Limit records are displayed. A Limit of zero will not limit the output. + - If the ExcludeFlag is TRUE, records matching entries in the CumData array are not + displayed. + + @pre The mInterestThreshold global variable is set to the shortest duration to be printed. + The mGaugeString and mUnicodeToken global arrays are used for temporary string storage. + They must not be in use by a calling function. + + @param[in] Limit The number of records to print. Zero is ALL. + @param[in] ExcludeFlag TRUE to exclude individual Cumulative items from display. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_ABORTED The user aborts the operation. + @return Others from a call to gBS->LocateHandleBuffer(). +**/ +EFI_STATUS +DumpAllTrace( + IN UINTN Limit, + IN BOOLEAN ExcludeFlag + ) +{ + MEASUREMENT_RECORD Measurement; + UINT64 ElapsedTime; + UINT64 Duration; + CHAR16 *IncFlag; + UINTN LogEntryKey; + UINTN Count; + UINTN Index; + UINTN TIndex; + + EFI_HANDLE *HandleBuffer; + UINTN HandleCount; + EFI_STATUS Status; + EFI_STRING StringPtrUnknown; + + StringPtrUnknown = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL); + IncFlag = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_ALL), NULL); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), mDpHiiHandle, + (IncFlag == NULL) ? StringPtrUnknown : IncFlag); + FreePool (StringPtrUnknown); + + // Get Handle information + // + Status = gBS->LocateHandleBuffer (AllHandles, NULL, NULL, &HandleCount, &HandleBuffer); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLES_ERROR), mDpHiiHandle, Status); + } + else { + // We have successfully populated the HandleBuffer + // Display ALL Measurement Records + // Up to Limit lines displayed + // Display only records with Elapsed times >= mInterestThreshold + // Display driver names in Module field for records with Handles. + // + if (mShowId) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_ALL_HEADR2), mDpHiiHandle); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_ALL_DASHES2), mDpHiiHandle); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_ALL_HEADR), mDpHiiHandle); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_DASHES), mDpHiiHandle); + } + + LogEntryKey = 0; + Count = 0; + Index = 0; + while ( WITHIN_LIMIT(Count, Limit) && + ((LogEntryKey = GetPerformanceMeasurementRecord ( + LogEntryKey, + &Measurement.Handle, + &Measurement.Token, + &Measurement.Module, + &Measurement.StartTimeStamp, + &Measurement.EndTimeStamp, + &Measurement.Identifier)) != 0) + ) + { + ++Index; // Count every record. First record is 1. + ElapsedTime = 0; + SHELL_FREE_NON_NULL (IncFlag); + if (Measurement.EndTimeStamp != 0) { + Duration = GetDuration (&Measurement); + ElapsedTime = DurationInMicroSeconds ( Duration ); + IncFlag = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_DP_COMPLETE), NULL); + } + else { + IncFlag = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_DP_INCOMPLETE), NULL); // Mark incomplete records + } + if (((Measurement.EndTimeStamp != 0) && (ElapsedTime < mInterestThreshold)) || + ((ExcludeFlag) && (GetCumulativeItem(&Measurement) >= 0)) + ) { // Ignore "uninteresting" or excluded records + continue; + } + ++Count; // Count the number of records printed + + // If Handle is non-zero, see if we can determine a name for the driver + AsciiStrToUnicodeStrS (Measurement.Module, mGaugeString, ARRAY_SIZE (mGaugeString)); // Use Module by default + AsciiStrToUnicodeStrS (Measurement.Token, mUnicodeToken, ARRAY_SIZE (mUnicodeToken)); + if (Measurement.Handle != NULL) { + // See if the Handle is in the HandleBuffer + for (TIndex = 0; TIndex < HandleCount; TIndex++) { + if (Measurement.Handle == HandleBuffer[TIndex]) { + DpGetNameFromHandle (HandleBuffer[TIndex]); + break; + } + } + } + + if (AsciiStrCmp (Measurement.Token, ALit_PEIM) == 0) { + UnicodeSPrint (mGaugeString, sizeof (mGaugeString), L"%g", Measurement.Handle); + } + + // Ensure that the argument strings are not too long. + mGaugeString[DP_GAUGE_STRING_LENGTH] = 0; + mUnicodeToken[13] = 0; + + if (mShowId) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_ALL_VARS2), mDpHiiHandle, + Index, // 1 based, Which measurement record is being printed + IncFlag, + Measurement.Handle, + mGaugeString, + mUnicodeToken, + ElapsedTime, + Measurement.Identifier + ); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_ALL_VARS), mDpHiiHandle, + Index, // 1 based, Which measurement record is being printed + IncFlag, + Measurement.Handle, + mGaugeString, + mUnicodeToken, + ElapsedTime + ); + } + if (ShellGetExecutionBreakFlag ()) { + Status = EFI_ABORTED; + break; + } + } + } + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + SHELL_FREE_NON_NULL (IncFlag); + + return Status; +} + +/** + Gather and print Raw Trace Records. + + All Trace measurements with a duration greater than or equal to + mInterestThreshold are printed without interpretation. + + The number of records displayed is controlled by: + - records with a duration less than mInterestThreshold microseconds are not displayed. + - No more than Limit records are displayed. A Limit of zero will not limit the output. + - If the ExcludeFlag is TRUE, records matching entries in the CumData array are not + displayed. + + @pre The mInterestThreshold global variable is set to the shortest duration to be printed. + + @param[in] Limit The number of records to print. Zero is ALL. + @param[in] ExcludeFlag TRUE to exclude individual Cumulative items from display. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_ABORTED The user aborts the operation. +**/ +EFI_STATUS +DumpRawTrace( + IN UINTN Limit, + IN BOOLEAN ExcludeFlag + ) +{ + MEASUREMENT_RECORD Measurement; + UINT64 ElapsedTime; + UINT64 Duration; + UINTN LogEntryKey; + UINTN Count; + UINTN Index; + + EFI_STRING StringPtr; + EFI_STRING StringPtrUnknown; + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + StringPtrUnknown = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL); + StringPtr = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_RAWTRACE), NULL); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), mDpHiiHandle, + (StringPtr == NULL) ? StringPtrUnknown : StringPtr); + FreePool (StringPtr); + FreePool (StringPtrUnknown); + + if (mShowId) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_RAW_HEADR2), mDpHiiHandle); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_RAW_DASHES2), mDpHiiHandle); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_RAW_HEADR), mDpHiiHandle); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_RAW_DASHES), mDpHiiHandle); + } + + LogEntryKey = 0; + Count = 0; + Index = 0; + while ( WITHIN_LIMIT(Count, Limit) && + ((LogEntryKey = GetPerformanceMeasurementRecord ( + LogEntryKey, + &Measurement.Handle, + &Measurement.Token, + &Measurement.Module, + &Measurement.StartTimeStamp, + &Measurement.EndTimeStamp, + &Measurement.Identifier)) != 0) + ) + { + ++Index; // Count every record. First record is 1. + ElapsedTime = 0; + if (Measurement.EndTimeStamp != 0) { + Duration = GetDuration (&Measurement); + ElapsedTime = DurationInMicroSeconds ( Duration ); + } + if ((ElapsedTime < mInterestThreshold) || + ((ExcludeFlag) && (GetCumulativeItem(&Measurement) >= 0)) + ) { // Ignore "uninteresting" or Excluded records + continue; + } + ++Count; // Count the number of records printed + + if (mShowId) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_RAW_VARS2), mDpHiiHandle, + Index, // 1 based, Which measurement record is being printed + Measurement.Handle, + Measurement.StartTimeStamp, + Measurement.EndTimeStamp, + Measurement.Token, + Measurement.Module, + Measurement.Identifier + ); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_RAW_VARS), mDpHiiHandle, + Index, // 1 based, Which measurement record is being printed + Measurement.Handle, + Measurement.StartTimeStamp, + Measurement.EndTimeStamp, + Measurement.Token, + Measurement.Module + ); + } + if (ShellGetExecutionBreakFlag ()) { + Status = EFI_ABORTED; + break; + } + } + return Status; +} + +/** + Gather and print Major Phase metrics. + +**/ +VOID +ProcessPhases( + VOID + ) +{ + MEASUREMENT_RECORD Measurement; + UINT64 BdsTimeoutValue; + UINT64 SecTime; + UINT64 PeiTime; + UINT64 DxeTime; + UINT64 BdsTime; + UINT64 ElapsedTime; + UINT64 Duration; + UINT64 Total; + EFI_STRING StringPtr; + UINTN LogEntryKey; + EFI_STRING StringPtrUnknown; + + BdsTimeoutValue = 0; + SecTime = 0; + PeiTime = 0; + DxeTime = 0; + BdsTime = 0; + // + // Get Execution Phase Statistics + // + StringPtrUnknown = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL); + StringPtr = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_PHASES), NULL); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), mDpHiiHandle, + (StringPtr == NULL) ? StringPtrUnknown : StringPtr); + FreePool (StringPtr); + FreePool (StringPtrUnknown); + + LogEntryKey = 0; + while ((LogEntryKey = GetPerformanceMeasurementRecord ( + LogEntryKey, + &Measurement.Handle, + &Measurement.Token, + &Measurement.Module, + &Measurement.StartTimeStamp, + &Measurement.EndTimeStamp, + &Measurement.Identifier)) != 0) + { + if (Measurement.EndTimeStamp == 0) { // Skip "incomplete" records + continue; + } + Duration = GetDuration (&Measurement); + if ( Measurement.Handle != NULL + && (AsciiStrCmp (Measurement.Token, ALit_BdsTO) == 0) + ) + { + BdsTimeoutValue = Duration; + } else if (AsciiStrCmp (Measurement.Token, ALit_SEC) == 0) { + SecTime = Duration; + } else if (AsciiStrCmp (Measurement.Token, ALit_PEI) == 0) { + PeiTime = Duration; + } else if (AsciiStrCmp (Measurement.Token, ALit_DXE) == 0) { + DxeTime = Duration; + } else if (AsciiStrCmp (Measurement.Token, ALit_BDS) == 0) { + BdsTime = Duration; + } + } + + Total = 0; + + // print SEC phase duration time + // + if (SecTime > 0) { + ElapsedTime = DurationInMicroSeconds ( SecTime ); // Calculate elapsed time in microseconds + Total += DivU64x32 (ElapsedTime, 1000); // Accumulate time in milliseconds + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SEC_PHASE), mDpHiiHandle, ElapsedTime); + } + + // print PEI phase duration time + // + if (PeiTime > 0) { + ElapsedTime = DivU64x32 (PeiTime, 1000000); + Total += ElapsedTime; + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PHASE_DURATION), mDpHiiHandle, ALit_PEI, ElapsedTime); + } + + // print DXE phase duration time + // + if (DxeTime > 0) { + ElapsedTime = DivU64x32 (DxeTime, 1000000); + Total += ElapsedTime; + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PHASE_DURATION), mDpHiiHandle, ALit_DXE, ElapsedTime); + } + + // print BDS phase duration time + // + if (BdsTime > 0) { + ElapsedTime = DivU64x32 (BdsTime, 1000000); + Total += ElapsedTime; + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PHASE_DURATION), mDpHiiHandle, ALit_BDS, ElapsedTime); + } + + if (BdsTimeoutValue > 0) { + ElapsedTime = DivU64x32 (BdsTimeoutValue, 1000000); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PHASE_BDSTO), mDpHiiHandle, ALit_BdsTO, ElapsedTime); + } + + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_TOTAL_DURATION), mDpHiiHandle, Total); +} + +/** + Gather and print Handle data. + + @param[in] ExcludeFlag TRUE to exclude individual Cumulative items from display. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_ABORTED The user aborts the operation. + @return Others from a call to gBS->LocateHandleBuffer(). +**/ +EFI_STATUS +ProcessHandles( + IN BOOLEAN ExcludeFlag + ) +{ + MEASUREMENT_RECORD Measurement; + UINT64 ElapsedTime; + UINT64 Duration; + EFI_HANDLE *HandleBuffer; + EFI_STRING StringPtr; + UINTN Index; + UINTN LogEntryKey; + UINTN Count; + UINTN HandleCount; + EFI_STATUS Status; + EFI_STRING StringPtrUnknown; + + StringPtrUnknown = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL); + StringPtr = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_DRIVERS), NULL); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), mDpHiiHandle, + (StringPtr == NULL) ? StringPtrUnknown : StringPtr); + FreePool (StringPtr); + FreePool (StringPtrUnknown); + + Status = gBS->LocateHandleBuffer (AllHandles, NULL, NULL, &HandleCount, &HandleBuffer); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLES_ERROR), mDpHiiHandle, Status); + } + else { +#if DP_DEBUG == 2 + Print (L"There are %,d Handles defined.\n", (Size / sizeof(HandleBuffer[0]))); +#endif + + if (mShowId) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLE_SECTION2), mDpHiiHandle); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLE_SECTION), mDpHiiHandle); + } + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_DASHES), mDpHiiHandle); + + LogEntryKey = 0; + Count = 0; + while ((LogEntryKey = GetPerformanceMeasurementRecord ( + LogEntryKey, + &Measurement.Handle, + &Measurement.Token, + &Measurement.Module, + &Measurement.StartTimeStamp, + &Measurement.EndTimeStamp, + &Measurement.Identifier)) != 0) + { + Count++; + Duration = GetDuration (&Measurement); + ElapsedTime = DurationInMicroSeconds ( Duration ); + if ((ElapsedTime < mInterestThreshold) || + (Measurement.EndTimeStamp == 0) || + (!IsCorePerf (&Measurement)) || + ((ExcludeFlag) && (GetCumulativeItem(&Measurement) >= 0)) + ) { // Ignore "uninteresting" or excluded records + continue; + } + mGaugeString[0] = 0; // Empty driver name by default + AsciiStrToUnicodeStrS (Measurement.Token, mUnicodeToken, ARRAY_SIZE (mUnicodeToken)); + // See if the Handle is in the HandleBuffer + for (Index = 0; Index < HandleCount; Index++) { + if (Measurement.Handle == HandleBuffer[Index]) { + DpGetNameFromHandle (HandleBuffer[Index]); // Name is put into mGaugeString + break; + } + } + // Ensure that the argument strings are not too long. + mGaugeString[DP_GAUGE_STRING_LENGTH] = 0; + mUnicodeToken[11] = 0; + if (mGaugeString[0] != 0) { + // Display the record if it has a valid handle. + if (mShowId) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLE_VARS2), mDpHiiHandle, + Count, // 1 based, Which measurement record is being printed + Index + 1, // 1 based, Which handle is being printed + mGaugeString, + mUnicodeToken, + ElapsedTime, + Measurement.Identifier + ); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLE_VARS), mDpHiiHandle, + Count, // 1 based, Which measurement record is being printed + Index + 1, // 1 based, Which handle is being printed + mGaugeString, + mUnicodeToken, + ElapsedTime + ); + } + } + if (ShellGetExecutionBreakFlag ()) { + Status = EFI_ABORTED; + break; + } + } + } + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + return Status; +} + +/** + Gather and print PEIM data. + + Only prints complete PEIM records + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_ABORTED The user aborts the operation. +**/ +EFI_STATUS +ProcessPeims( + VOID +) +{ + MEASUREMENT_RECORD Measurement; + UINT64 Duration; + UINT64 ElapsedTime; + EFI_STRING StringPtr; + UINTN LogEntryKey; + UINTN TIndex; + EFI_STRING StringPtrUnknown; + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + StringPtrUnknown = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL); + StringPtr = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_PEIMS), NULL); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), mDpHiiHandle, + (StringPtr == NULL) ? StringPtrUnknown : StringPtr); + FreePool (StringPtr); + FreePool (StringPtrUnknown); + + if (mShowId) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PEIM_SECTION2), mDpHiiHandle); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PEIM_SECTION), mDpHiiHandle); + } + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_DASHES), mDpHiiHandle); + TIndex = 0; + LogEntryKey = 0; + while ((LogEntryKey = GetPerformanceMeasurementRecord ( + LogEntryKey, + &Measurement.Handle, + &Measurement.Token, + &Measurement.Module, + &Measurement.StartTimeStamp, + &Measurement.EndTimeStamp, + &Measurement.Identifier)) != 0) + { + TIndex++; + if ((Measurement.EndTimeStamp == 0) || + (AsciiStrCmp (Measurement.Token, ALit_PEIM) != 0) + ) { + continue; + } + + Duration = GetDuration (&Measurement); + ElapsedTime = DurationInMicroSeconds ( Duration ); // Calculate elapsed time in microseconds + if (ElapsedTime >= mInterestThreshold) { + // PEIM FILE Handle is the start address of its FFS file that contains its file guid. + if (mShowId) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PEIM_VARS2), mDpHiiHandle, + TIndex, // 1 based, Which measurement record is being printed + Measurement.Handle, // file guid + ElapsedTime, + Measurement.Identifier + ); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PEIM_VARS), mDpHiiHandle, + TIndex, // 1 based, Which measurement record is being printed + Measurement.Handle, // file guid + ElapsedTime + ); + } + } + if (ShellGetExecutionBreakFlag ()) { + Status = EFI_ABORTED; + break; + } + } + return Status; +} + +/** + Gather and print global data. + + Strips out incomplete or "Execution Phase" records + Only prints records where Handle is NULL + Increment TIndex for every record, even skipped ones, so that we have an + indication of every measurement record taken. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_ABORTED The user aborts the operation. +**/ +EFI_STATUS +ProcessGlobal( + VOID +) +{ + MEASUREMENT_RECORD Measurement; + UINT64 Duration; + UINT64 ElapsedTime; + EFI_STRING StringPtr; + UINTN LogEntryKey; + UINTN Index; // Index, or number, of the measurement record being processed + EFI_STRING StringPtrUnknown; + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + StringPtrUnknown = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL); + StringPtr = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_GENERAL), NULL); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), mDpHiiHandle, + (StringPtr == NULL) ? StringPtrUnknown: StringPtr); + FreePool (StringPtr); + FreePool (StringPtrUnknown); + + if (mShowId) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_GLOBAL_SECTION2), mDpHiiHandle); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_GLOBAL_SECTION), mDpHiiHandle); + } + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_DASHES), mDpHiiHandle); + + Index = 1; + LogEntryKey = 0; + + while ((LogEntryKey = GetPerformanceMeasurementRecord ( + LogEntryKey, + &Measurement.Handle, + &Measurement.Token, + &Measurement.Module, + &Measurement.StartTimeStamp, + &Measurement.EndTimeStamp, + &Measurement.Identifier)) != 0) + { + AsciiStrToUnicodeStrS (Measurement.Module, mGaugeString, ARRAY_SIZE (mGaugeString)); + AsciiStrToUnicodeStrS (Measurement.Token, mUnicodeToken, ARRAY_SIZE (mUnicodeToken)); + mGaugeString[25] = 0; + mUnicodeToken[31] = 0; + if ( ! ( IsPhase( &Measurement) || + IsCorePerf (&Measurement) || + (Measurement.EndTimeStamp == 0) + )) + { + Duration = GetDuration (&Measurement); + ElapsedTime = DurationInMicroSeconds ( Duration ); + if (ElapsedTime >= mInterestThreshold) { + if (mShowId) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_GLOBAL_VARS2), mDpHiiHandle, + Index, + mGaugeString, + mUnicodeToken, + ElapsedTime, + Measurement.Identifier + ); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_GLOBAL_VARS), mDpHiiHandle, + Index, + mGaugeString, + mUnicodeToken, + ElapsedTime + ); + } + } + } + if (ShellGetExecutionBreakFlag ()) { + Status = EFI_ABORTED; + break; + } + Index++; + } + return Status; +} + +/** + Gather and print cumulative data. + + Traverse the measurement records and:
+ For each record with a Token listed in the CumData array:
+ - Update the instance count and the total, minimum, and maximum durations. + Finally, print the gathered cumulative statistics. + + @param[in] CustomCumulativeData A pointer to the custom cumulative data. + +**/ +VOID +ProcessCumulative( + IN PERF_CUM_DATA *CustomCumulativeData OPTIONAL + ) +{ + UINT64 AvgDur; // the computed average duration + UINT64 Dur; + UINT64 MinDur; + UINT64 MaxDur; + EFI_STRING StringPtr; + UINTN TIndex; + EFI_STRING StringPtrUnknown; + + StringPtrUnknown = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL); + StringPtr = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_CUMULATIVE), NULL); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), mDpHiiHandle, + (StringPtr == NULL) ? StringPtrUnknown: StringPtr); + FreePool (StringPtr); + FreePool (StringPtrUnknown); + + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_CUMULATIVE_SECT_1), mDpHiiHandle); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_CUMULATIVE_SECT_2), mDpHiiHandle); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_DASHES), mDpHiiHandle); + + for ( TIndex = 0; TIndex < NumCum; ++TIndex) { + if (CumData[TIndex].Count != 0) { + AvgDur = DivU64x32 (CumData[TIndex].Duration, CumData[TIndex].Count); + AvgDur = DurationInMicroSeconds(AvgDur); + Dur = DurationInMicroSeconds(CumData[TIndex].Duration); + MaxDur = DurationInMicroSeconds(CumData[TIndex].MaxDur); + MinDur = DurationInMicroSeconds(CumData[TIndex].MinDur); + + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_CUMULATIVE_STATS), mDpHiiHandle, + CumData[TIndex].Name, + CumData[TIndex].Count, + Dur, + AvgDur, + MinDur, + MaxDur + ); + } + } + + // + // Print the custom cumulative data. + // + if (CustomCumulativeData != NULL) { + if (CustomCumulativeData->Count != 0) { + AvgDur = DivU64x32 (CustomCumulativeData->Duration, CustomCumulativeData->Count); + AvgDur = DurationInMicroSeconds (AvgDur); + Dur = DurationInMicroSeconds (CustomCumulativeData->Duration); + MaxDur = DurationInMicroSeconds (CustomCumulativeData->MaxDur); + MinDur = DurationInMicroSeconds (CustomCumulativeData->MinDur); + } else { + AvgDur = 0; + Dur = 0; + MaxDur = 0; + MinDur = 0; + } + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_CUMULATIVE_STATS), mDpHiiHandle, + CustomCumulativeData->Name, + CustomCumulativeData->Count, + Dur, + AvgDur, + MinDur, + MaxDur + ); + } +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpUtilities.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpUtilities.c new file mode 100644 index 00000000..8d84e69b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpUtilities.c @@ -0,0 +1,422 @@ +/** @file + Utility functions used by the Dp application. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved. + (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include "Dp.h" +#include "Literals.h" +#include "DpInternal.h" + +/** + Calculate an event's duration in timer ticks. + + Given the count direction and the event's start and end timer values, + calculate the duration of the event in timer ticks. Information for + the current measurement is pointed to by the parameter. + + If the measurement's start time is 1, it indicates that the developer + is indicating that the measurement began at the release of reset. + The start time is adjusted to the timer's starting count before performing + the elapsed time calculation. + + The calculated duration, in ticks, is the absolute difference between + the measurement's ending and starting counts. + + @param Measurement Pointer to a MEASUREMENT_RECORD structure containing + data for the current measurement. + + @return The 64-bit duration of the event. +**/ +UINT64 +GetDuration ( + IN OUT MEASUREMENT_RECORD *Measurement + ) +{ + UINT64 Duration; + BOOLEAN Error; + + if (Measurement->EndTimeStamp == 0) { + return 0; + } + + Duration = Measurement->EndTimeStamp - Measurement->StartTimeStamp; + Error = (BOOLEAN)(Duration > Measurement->EndTimeStamp); + + if (Error) { + DEBUG ((EFI_D_ERROR, ALit_TimerLibError)); + Duration = 0; + } + return Duration; +} + +/** + Determine whether the Measurement record is for an EFI Phase. + + The Token and Module members of the measurement record are checked. + Module must be empty and Token must be one of SEC, PEI, DXE, BDS, or SHELL. + + @param[in] Measurement A pointer to the Measurement record to test. + + @retval TRUE The measurement record is for an EFI Phase. + @retval FALSE The measurement record is NOT for an EFI Phase. +**/ +BOOLEAN +IsPhase( + IN MEASUREMENT_RECORD *Measurement + ) +{ + BOOLEAN RetVal; + + RetVal = (BOOLEAN)( + ((AsciiStrCmp (Measurement->Token, ALit_SEC) == 0) || + (AsciiStrCmp (Measurement->Token, ALit_PEI) == 0) || + (AsciiStrCmp (Measurement->Token, ALit_DXE) == 0) || + (AsciiStrCmp (Measurement->Token, ALit_BDS) == 0)) + ); + return RetVal; +} + +/** + Determine whether the Measurement record is for core code. + + @param[in] Measurement A pointer to the Measurement record to test. + + @retval TRUE The measurement record is used for core. + @retval FALSE The measurement record is NOT used for core. + +**/ +BOOLEAN +IsCorePerf( + IN MEASUREMENT_RECORD *Measurement + ) +{ + BOOLEAN RetVal; + + RetVal = (BOOLEAN)( + ((Measurement->Identifier == MODULE_START_ID) || + (Measurement->Identifier == MODULE_END_ID) || + (Measurement->Identifier == MODULE_LOADIMAGE_START_ID) || + (Measurement->Identifier == MODULE_LOADIMAGE_END_ID) || + (Measurement->Identifier == MODULE_DB_START_ID) || + (Measurement->Identifier == MODULE_DB_END_ID) || + (Measurement->Identifier == MODULE_DB_SUPPORT_START_ID) || + (Measurement->Identifier == MODULE_DB_SUPPORT_END_ID) || + (Measurement->Identifier == MODULE_DB_STOP_START_ID) || + (Measurement->Identifier == MODULE_DB_STOP_START_ID)) + ); + return RetVal; +} + +/** + 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 converted + to Unicode and copied into UnicodeBuffer. The name is truncated, + if necessary, to ensure that UnicodeBuffer is not overrun. + + @param[in] PdbFileName Pdb file name. + @param[out] UnicodeBuffer The resultant Unicode File Name. + +**/ +VOID +DpGetShortPdbFileName ( + IN CHAR8 *PdbFileName, + OUT CHAR16 *UnicodeBuffer + ) +{ + UINTN IndexA; // Current work location within an ASCII string. + UINTN IndexU; // Current work location within a Unicode string. + UINTN StartIndex; + UINTN EndIndex; + + ZeroMem (UnicodeBuffer, (DP_GAUGE_STRING_LENGTH + 1) * sizeof (CHAR16)); + + if (PdbFileName == NULL) { + StrnCpyS (UnicodeBuffer, DP_GAUGE_STRING_LENGTH + 1, L" ", 1); + } else { + StartIndex = 0; + for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++) + ; + for (IndexA = 0; PdbFileName[IndexA] != 0; IndexA++) { + if ((PdbFileName[IndexA] == '\\') || (PdbFileName[IndexA] == '/')) { + StartIndex = IndexA + 1; + } + + if (PdbFileName[IndexA] == '.') { + EndIndex = IndexA; + } + } + + IndexU = 0; + for (IndexA = StartIndex; IndexA < EndIndex; IndexA++) { + UnicodeBuffer[IndexU] = (CHAR16) PdbFileName[IndexA]; + IndexU++; + if (IndexU >= DP_GAUGE_STRING_LENGTH) { + UnicodeBuffer[DP_GAUGE_STRING_LENGTH] = 0; + break; + } + } + } +} + +/** + Get a human readable name for an image handle. + The following methods will be tried orderly: + 1. Image PDB + 2. ComponentName2 protocol + 3. FFS UI section + 4. Image GUID + 5. Image DevicePath + 6. Unknown Driver Name + + @param[in] Handle + + @post The resulting Unicode name string is stored in the + mGaugeString global array. + +**/ +VOID +DpGetNameFromHandle ( + IN EFI_HANDLE Handle + ) +{ + EFI_STATUS Status; + EFI_LOADED_IMAGE_PROTOCOL *Image; + CHAR8 *PdbFileName; + EFI_DRIVER_BINDING_PROTOCOL *DriverBinding; + EFI_STRING StringPtr; + EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_GUID *NameGuid; + CHAR16 *NameString; + UINTN StringSize; + CHAR8 *PlatformLanguage; + CHAR8 *BestLanguage; + EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2; + + Image = NULL; + LoadedImageDevicePath = NULL; + DevicePath = NULL; + + // + // Method 1: Get the name string from image PDB + // + Status = gBS->HandleProtocol ( + Handle, + &gEfiLoadedImageProtocolGuid, + (VOID **) &Image + ); + + if (EFI_ERROR (Status)) { + Status = gBS->OpenProtocol ( + Handle, + &gEfiDriverBindingProtocolGuid, + (VOID **) &DriverBinding, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + Status = gBS->HandleProtocol ( + DriverBinding->ImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID **) &Image + ); + } + } + + if (!EFI_ERROR (Status)) { + PdbFileName = PeCoffLoaderGetPdbPointer (Image->ImageBase); + + if (PdbFileName != NULL) { + DpGetShortPdbFileName (PdbFileName, mGaugeString); + return; + } + } + + // + // Method 2: Get the name string from ComponentName2 protocol + // + Status = gBS->HandleProtocol ( + Handle, + &gEfiComponentName2ProtocolGuid, + (VOID **) &ComponentName2 + ); + if (!EFI_ERROR (Status)) { + // + // Firstly use platform language setting, secondly use driver's first supported language. + // + GetVariable2 (L"PlatformLang", &gEfiGlobalVariableGuid, (VOID**)&PlatformLanguage, NULL); + BestLanguage = GetBestLanguage( + ComponentName2->SupportedLanguages, + FALSE, + (PlatformLanguage != NULL) ? PlatformLanguage : "", + ComponentName2->SupportedLanguages, + NULL + ); + SHELL_FREE_NON_NULL (PlatformLanguage); + + Status = ComponentName2->GetDriverName ( + ComponentName2, + BestLanguage != NULL ? BestLanguage : "en-US", + &StringPtr + ); + if (!EFI_ERROR (Status)) { + SHELL_FREE_NON_NULL (BestLanguage); + StrnCpyS (mGaugeString, DP_GAUGE_STRING_LENGTH + 1, StringPtr, DP_GAUGE_STRING_LENGTH); + mGaugeString[DP_GAUGE_STRING_LENGTH] = 0; + return; + } + } + + Status = gBS->HandleProtocol ( + Handle, + &gEfiLoadedImageDevicePathProtocolGuid, + (VOID **) &LoadedImageDevicePath + ); + if (!EFI_ERROR (Status) && (LoadedImageDevicePath != NULL)) { + DevicePath = LoadedImageDevicePath; + } else if (Image != NULL) { + DevicePath = Image->FilePath; + } + + if (DevicePath != NULL) { + // + // Try to get image GUID from image DevicePath + // + NameGuid = NULL; + while (!IsDevicePathEndType (DevicePath)) { + NameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) DevicePath); + if (NameGuid != NULL) { + break; + } + DevicePath = NextDevicePathNode (DevicePath); + } + + if (NameGuid != NULL) { + // + // Try to get the image's FFS UI section by image GUID + // + NameString = NULL; + StringSize = 0; + Status = GetSectionFromAnyFv ( + NameGuid, + EFI_SECTION_USER_INTERFACE, + 0, + (VOID **) &NameString, + &StringSize + ); + + if (!EFI_ERROR (Status)) { + // + // Method 3. Get the name string from FFS UI section + // + StrnCpyS (mGaugeString, DP_GAUGE_STRING_LENGTH + 1, NameString, DP_GAUGE_STRING_LENGTH); + mGaugeString[DP_GAUGE_STRING_LENGTH] = 0; + FreePool (NameString); + } else { + // + // Method 4: Get the name string from image GUID + // + UnicodeSPrint (mGaugeString, sizeof (mGaugeString), L"%g", NameGuid); + } + return; + } else { + // + // Method 5: Get the name string from image DevicePath + // + NameString = ConvertDevicePathToText (DevicePath, TRUE, FALSE); + if (NameString != NULL) { + StrnCpyS (mGaugeString, DP_GAUGE_STRING_LENGTH + 1, NameString, DP_GAUGE_STRING_LENGTH); + mGaugeString[DP_GAUGE_STRING_LENGTH] = 0; + FreePool (NameString); + return; + } + } + } + + // + // Method 6: Unknown Driver Name + // + StringPtr = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_DP_ERROR_NAME), NULL); + ASSERT (StringPtr != NULL); + StrnCpyS (mGaugeString, DP_GAUGE_STRING_LENGTH + 1, StringPtr, DP_GAUGE_STRING_LENGTH); + FreePool (StringPtr); +} + +/** + Calculate the Duration in microseconds. + + Duration is multiplied by 1000, instead of Frequency being divided by 1000 or + multiplying the result by 1000, in order to maintain precision. Since Duration is + a 64-bit value, multiplying it by 1000 is unlikely to produce an overflow. + + The time is calculated as (Duration * 1000) / Timer_Frequency. + + @param[in] Duration The event duration in timer ticks. + + @return A 64-bit value which is the Elapsed time in microseconds. +**/ +UINT64 +DurationInMicroSeconds ( + IN UINT64 Duration + ) +{ + return DivU64x32 (Duration, 1000); +} + +/** + Get index of Measurement Record's match in the CumData array. + + If the Measurement's Token value matches a Token in one of the CumData + records, the index of the matching record is returned. The returned + index is a signed value so that negative values can indicate that + the Measurement didn't match any entry in the CumData array. + + @param[in] Measurement A pointer to a Measurement Record to match against the CumData array. + + @retval <0 Token is not in the CumData array. + @retval >=0 Return value is the index into CumData where Token is found. +**/ +INTN +GetCumulativeItem( + IN MEASUREMENT_RECORD *Measurement + ) +{ + INTN Index; + + for( Index = 0; Index < (INTN)NumCum; ++Index) { + if (AsciiStrCmp (Measurement->Token, CumData[Index].Name) == 0) { + return Index; // Exit, we found a match + } + } + // If the for loop exits, Token was not found. + return -1; // Indicate failure +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Literals.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Literals.c new file mode 100644 index 00000000..ec99fe4b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Literals.c @@ -0,0 +1,22 @@ +/** @file + Definitions of ASCII string literals used by DP. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include + +// ASCII String literals which probably don't need translation +CHAR8 const ALit_TimerLibError[] = "Timer library instance error!\n"; +CHAR8 const ALit_SEC[] = SEC_TOK; +CHAR8 const ALit_DXE[] = DXE_TOK; +CHAR8 const ALit_PEI[] = PEI_TOK; +CHAR8 const ALit_BDS[] = BDS_TOK; +CHAR8 const ALit_START_IMAGE[] = START_IMAGE_TOK; +CHAR8 const ALit_LOAD_IMAGE[] = LOAD_IMAGE_TOK; +CHAR8 const ALit_DB_START[] = DRIVERBINDING_START_TOK; +CHAR8 const ALit_DB_SUPPORT[] = DRIVERBINDING_SUPPORT_TOK; +CHAR8 const ALit_DB_STOP[] = DRIVERBINDING_STOP_TOK; + +CHAR8 const ALit_BdsTO[] = "BdsTimeOut"; +CHAR8 const ALit_PEIM[] = "PEIM"; diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Literals.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Literals.h new file mode 100644 index 00000000..c0ef8791 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Literals.h @@ -0,0 +1,26 @@ +/** @file + Declarations of ASCII string literals used by DP. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _LITERALS_H_ +#define _LITERALS_H_ + +// ASCII String literals which probably don't need translation +extern CHAR8 const ALit_TimerLibError[]; +extern CHAR8 const ALit_SEC[]; +extern CHAR8 const ALit_DXE[]; +extern CHAR8 const ALit_SHELL[]; +extern CHAR8 const ALit_PEI[]; +extern CHAR8 const ALit_BDS[]; +extern CHAR8 const ALit_PEIM[]; +extern CHAR8 const ALit_START_IMAGE[]; +extern CHAR8 const ALit_LOAD_IMAGE[]; +extern CHAR8 const ALit_DB_START[]; +extern CHAR8 const ALit_DB_SUPPORT[]; +extern CHAR8 const ALit_DB_STOP[]; +extern CHAR8 const ALit_BdsTO[]; +extern CHAR8 const ALit_PEIM[]; + +#endif // _LITERALS_H_ diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.c new file mode 100644 index 00000000..5173ac1e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.c @@ -0,0 +1,1905 @@ +/** @file + The implementation for the 'http' Shell command. + + Copyright (c) 2015, ARM Ltd. All rights reserved.
+ Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP
+ Copyright (c) 2020, Broadcom. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "Http.h" + +#define IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH 32 + +// +// Constant strings and definitions related to the message +// indicating the amount of progress in the dowloading of a HTTP file. +// + +// +// Number of steps in the progression slider. +// +#define HTTP_PROGRESS_SLIDER_STEPS \ + ((sizeof (HTTP_PROGR_FRAME) / sizeof (CHAR16)) - 3) + +// +// Size in number of characters plus one (final zero) of the message to +// indicate the progress of an HTTP download. The format is "[(progress slider: +// 40 characters)] (nb of KBytes downloaded so far: 7 characters) Kb". There +// are thus the number of characters in HTTP_PROGR_FRAME[] plus 11 characters +// (2 // spaces, "Kb" and seven characters for the number of KBytes). +// +#define HTTP_PROGRESS_MESSAGE_SIZE \ + ((sizeof (HTTP_PROGR_FRAME) / sizeof (CHAR16)) + 12) + +// +// Buffer size. Note that larger buffer does not mean better speed. +// +#define DEFAULT_BUF_SIZE SIZE_32KB +#define MAX_BUF_SIZE SIZE_4MB + +#define MIN_PARAM_COUNT 2 +#define MAX_PARAM_COUNT 4 +#define NEED_REDIRECTION(Code) \ + (((Code >= HTTP_STATUS_300_MULTIPLE_CHOICES) \ + && (Code <= HTTP_STATUS_307_TEMPORARY_REDIRECT)) \ + || (Code == HTTP_STATUS_308_PERMANENT_REDIRECT)) + +#define CLOSE_HTTP_HANDLE(ControllerHandle,HttpChildHandle) \ + do { \ + if (HttpChildHandle) { \ + CloseProtocolAndDestroyServiceChild ( \ + ControllerHandle, \ + &gEfiHttpServiceBindingProtocolGuid, \ + &gEfiHttpProtocolGuid, \ + HttpChildHandle \ + ); \ + HttpChildHandle = NULL; \ + } \ + } while (0) + +typedef enum { + HdrHost, + HdrConn, + HdrAgent, + HdrMax +} HDR_TYPE; + +#define USER_AGENT_HDR "Mozilla/5.0 (EDK2; Linux) Gecko/20100101 Firefox/79.0" + +#define TIMER_MAX_TIMEOUT_S 10 + +// +// File name to use when Uri ends with "/". +// +#define DEFAULT_HTML_FILE L"index.html" +#define DEFAULT_HTTP_PROTO L"http" + +// +// String to delete the HTTP progress message to be able to update it : +// (HTTP_PROGRESS_MESSAGE_SIZE-1) '\b'. +// +#define HTTP_PROGRESS_DEL \ + L"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\ +\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" + +#define HTTP_KB L"\b\b\b\b\b\b\b\b\b\b" +// +// Frame for the progression slider. +// +#define HTTP_PROGR_FRAME L"[ ]" + +// +// Improve readability by using these macros. +// +#define PRINT_HII(token,...) \ + ShellPrintHiiEx (\ + -1, -1, NULL, token, mHttpHiiHandle, __VA_ARGS__) + +#define PRINT_HII_APP(token,value) \ + PRINT_HII (token, HTTP_APP_NAME, value) + +// +// TimeBaseLib.h constants. +// These will be removed once the library gets fixed. +// + +// +// Define EPOCH (1970-JANUARY-01) in the Julian Date representation. +// +#define EPOCH_JULIAN_DATE 2440588 + +// +// Seconds per unit. +// +#define SEC_PER_MIN ((UINTN) 60) +#define SEC_PER_HOUR ((UINTN) 3600) +#define SEC_PER_DAY ((UINTN) 86400) + +// +// String descriptions for server errors. +// +STATIC CONST CHAR16 *ErrStatusDesc[] = +{ + L"400 Bad Request", + L"401 Unauthorized", + L"402 Payment required", + L"403 Forbidden", + L"404 Not Found", + L"405 Method not allowed", + L"406 Not acceptable", + L"407 Proxy authentication required", + L"408 Request time out", + L"409 Conflict", + L"410 Gone", + L"411 Length required", + L"412 Precondition failed", + L"413 Request entity too large", + L"414 Request URI to large", + L"415 Unsupported media type", + L"416 Requested range not satisfied", + L"417 Expectation failed", + L"500 Internal server error", + L"501 Not implemented", + L"502 Bad gateway", + L"503 Service unavailable", + L"504 Gateway timeout", + L"505 HTTP version not supported" +}; + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-i", TypeValue}, + {L"-k", TypeFlag}, + {L"-l", TypeValue}, + {L"-m", TypeFlag}, + {L"-s", TypeValue}, + {L"-t", TypeValue}, + {NULL , TypeMax} +}; + +// +// Local File Handle. +// +STATIC SHELL_FILE_HANDLE mFileHandle = NULL; + +// +// Path of the local file, Unicode encoded. +// +STATIC CONST CHAR16 *mLocalFilePath; + +STATIC BOOLEAN gRequestCallbackComplete = FALSE; +STATIC BOOLEAN gResponseCallbackComplete = FALSE; + +STATIC BOOLEAN gHttpError; + +EFI_HII_HANDLE mHttpHiiHandle; + +// +// Functions declarations. +// + +/** + Check and convert the UINT16 option values of the 'http' command. + + @param[in] ValueStr Value as an Unicode encoded string. + @param[out] Value UINT16 value. + + @retval TRUE The value was returned. + @retval FALSE A parsing error occured. +**/ +STATIC +BOOLEAN +StringToUint16 ( + IN CONST CHAR16 *ValueStr, + OUT UINT16 *Value + ); + +/** + Get the name of the NIC. + + @param[in] ControllerHandle The network physical device handle. + @param[in] NicNumber The network physical device number. + @param[out] NicName Address where to store the NIC name. + The memory area has to be at least + IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH + double byte wide. + + @retval EFI_SUCCESS The name of the NIC was returned. + @retval Others The creation of the child for the Managed + Network Service failed or the opening of + the Managed Network Protocol failed or + the operational parameters for the + Managed Network Protocol could not be + read. +**/ +STATIC +EFI_STATUS +GetNicName ( + IN EFI_HANDLE ControllerHandle, + IN UINTN NicNumber, + OUT CHAR16 *NicName + ); + +/** + Create a child for the service identified by its service binding protocol GUID + and get from the child the interface of the protocol identified by its GUID. + + @param[in] ControllerHandle Controller handle. + @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the + service to be created. + @param[in] ProtocolGuid GUID of the protocol to be open. + @param[out] ChildHandle Address where the handler of the + created child is returned. NULL is + returned in case of error. + @param[out] Interface Address where a pointer to the + protocol interface is returned in + case of success. + + @retval EFI_SUCCESS The child was created and the protocol opened. + @retval Others Either the creation of the child or the opening + of the protocol failed. +**/ +STATIC +EFI_STATUS +CreateServiceChildAndOpenProtocol ( + IN EFI_HANDLE ControllerHandle, + IN EFI_GUID *ServiceBindingProtocolGuid, + IN EFI_GUID *ProtocolGuid, + OUT EFI_HANDLE *ChildHandle, + OUT VOID **Interface + ); + +/** + Close the protocol identified by its GUID on the child handle of the service + identified by its service binding protocol GUID, then destroy the child + handle. + + @param[in] ControllerHandle Controller handle. + @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the + service to be destroyed. + @param[in] ProtocolGuid GUID of the protocol to be closed. + @param[in] ChildHandle Handle of the child to be destroyed. + +**/ +STATIC +VOID +CloseProtocolAndDestroyServiceChild ( + IN EFI_HANDLE ControllerHandle, + IN EFI_GUID *ServiceBindingProtocolGuid, + IN EFI_GUID *ProtocolGuid, + IN EFI_HANDLE ChildHandle + ); + +/** + Worker function that download the data of a file from an HTTP server given + the path of the file and its size. + + @param[in] Context A pointer to the download context. + + @retval EFI_SUCCESS The file was downloaded. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval Others The downloading of the file + from the server failed. +**/ +STATIC +EFI_STATUS +DownloadFile ( + IN HTTP_DOWNLOAD_CONTEXT *Context, + IN EFI_HANDLE ControllerHandle, + IN CHAR16 *NicName + ); + +/** + Cleans off leading and trailing spaces and tabs. + + @param[in] String pointer to the string to trim them off. + + @retval EFI_SUCCESS No errors. + @retval EFI_INVALID_PARAMETER String pointer is NULL. +**/ +STATIC +EFI_STATUS +TrimSpaces ( + IN CHAR16 *String + ) +{ + CHAR16 *Str; + UINTN Len; + + ASSERT (String != NULL); + + if (String == NULL) { + return EFI_INVALID_PARAMETER; + } + + Str = String; + + // + // Remove any whitespace at the beginning of the Str. + // + while (*Str == L' ' || *Str == L'\t') { + Str++; + } + + // + // Remove any whitespace at the end of the Str. + // + do { + Len = StrLen (Str); + if (!Len || (Str[Len - 1] != L' ' && Str[Len - 1] != '\t')) { + break; + } + + Str[Len - 1] = CHAR_NULL; + } while (Len); + + CopyMem (String, Str, StrSize (Str)); + + return EFI_SUCCESS; +} + +// +// Callbacks for request and response. +// We just acknowledge that operation has completed here. +// + +/** + Callback to set the request completion flag. + + @param[in] Event: The event. + @param[in] Context: pointer to Notification Context. + **/ +STATIC +VOID +EFIAPI +RequestCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + gRequestCallbackComplete = TRUE; +} + +/** + Callback to set the response completion flag. + @param[in] Event: The event. + @param[in] Context: pointer to Notification Context. + **/ +STATIC +VOID +EFIAPI +ResponseCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + gResponseCallbackComplete = TRUE; +} + +// +// Set of functions from TimeBaseLib. +// This will be removed once TimeBaseLib is enabled for ShellPkg. +// + +/** + Calculate Epoch days. + + @param[in] Time - a pointer to the EFI_TIME abstraction. + + @retval Number of days elapsed since EPOCH_JULIAN_DAY. + **/ +STATIC +UINTN +EfiGetEpochDays ( + IN EFI_TIME *Time + ) +{ + UINTN a; + UINTN y; + UINTN m; + // + // Absolute Julian Date representation of the supplied Time. + // + UINTN JulianDate; + // + // Number of days elapsed since EPOCH_JULIAN_DAY. + // + UINTN EpochDays; + + a = (14 - Time->Month) / 12 ; + y = Time->Year + 4800 - a; + m = Time->Month + (12 * a) - 3; + + JulianDate = Time->Day + ((153 * m + 2) / 5) + (365 * y) + (y / 4) - + (y / 100) + (y / 400) - 32045; + + ASSERT (JulianDate >= EPOCH_JULIAN_DATE); + EpochDays = JulianDate - EPOCH_JULIAN_DATE; + + return EpochDays; +} + +/** + Converts EFI_TIME to Epoch seconds + (elapsed since 1970 JANUARY 01, 00:00:00 UTC). + + @param[in] Time: a pointer to EFI_TIME abstraction. + **/ +STATIC +UINTN +EFIAPI +EfiTimeToEpoch ( + IN EFI_TIME *Time + ) +{ + // + // Number of days elapsed since EPOCH_JULIAN_DAY. + // + UINTN EpochDays; + UINTN EpochSeconds; + + EpochDays = EfiGetEpochDays (Time); + + EpochSeconds = (EpochDays * SEC_PER_DAY) + + ((UINTN)Time->Hour * SEC_PER_HOUR) + + (Time->Minute * SEC_PER_MIN) + Time->Second; + + return EpochSeconds; +} + +/** + Function for 'http' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). + + @retval SHELL_SUCCESS The 'http' command completed successfully. + @retval SHELL_ABORTED The Shell Library initialization failed. + @retval SHELL_INVALID_PARAMETER At least one of the command's arguments is + not valid. + @retval SHELL_OUT_OF_RESOURCES A memory allocation failed. + @retval SHELL_NOT_FOUND Network Interface Card not found. + @retval SHELL_UNSUPPORTED Command was valid, but the server returned + a status code indicating some error. + Examine the file requested for error body. +**/ +SHELL_STATUS +RunHttp ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *CheckPackage; + UINTN ParamCount; + UINTN HandleCount; + UINTN NicNumber; + UINTN InitialSize; + UINTN ParamOffset; + UINTN StartSize; + CHAR16 *ProblemParam; + CHAR16 NicName[IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH]; + CHAR16 *Walker1; + CHAR16 *VStr; + CONST CHAR16 *UserNicName; + CONST CHAR16 *ValueStr; + CONST CHAR16 *RemoteFilePath; + CONST CHAR16 *Walker; + EFI_HTTPv4_ACCESS_POINT IPv4Node; + EFI_HANDLE *Handles; + EFI_HANDLE ControllerHandle; + HTTP_DOWNLOAD_CONTEXT Context; + BOOLEAN NicFound; + + ProblemParam = NULL; + RemoteFilePath = NULL; + NicFound = FALSE; + Handles = NULL; + + // + // Initialize the Shell library (we must be in non-auto-init...). + // + ParamOffset = 0; + gHttpError = FALSE; + + Status = ShellInitialize (); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return SHELL_ABORTED; + } + + ZeroMem (&Context, sizeof (Context)); + + // + // Parse the command line. + // + Status = ShellCommandLineParse ( + ParamList, + &CheckPackage, + &ProblemParam, + TRUE + ); + if (EFI_ERROR (Status)) { + if ((Status == EFI_VOLUME_CORRUPTED) + && (ProblemParam != NULL)) + { + PRINT_HII_APP (STRING_TOKEN (STR_GEN_PROBLEM), ProblemParam); + SHELL_FREE_NON_NULL (ProblemParam); + } else { + ASSERT (FALSE); + } + + goto Error; + } + + // + // Check the number of parameters. + // + Status = EFI_INVALID_PARAMETER; + + ParamCount = ShellCommandLineGetCount (CheckPackage); + if (ParamCount > MAX_PARAM_COUNT) { + PRINT_HII_APP (STRING_TOKEN (STR_GEN_TOO_MANY), NULL); + goto Error; + } + + if (ParamCount < MIN_PARAM_COUNT) { + PRINT_HII_APP (STRING_TOKEN (STR_GEN_TOO_FEW), NULL); + goto Error; + } + + ZeroMem (&Context.HttpConfigData, sizeof (Context.HttpConfigData)); + ZeroMem (&IPv4Node, sizeof (IPv4Node)); + IPv4Node.UseDefaultAddress = TRUE; + + Context.HttpConfigData.HttpVersion = HttpVersion11; + Context.HttpConfigData.AccessPoint.IPv4Node = &IPv4Node; + + // + // Get the host address (not necessarily IPv4 format). + // + ValueStr = ShellCommandLineGetRawValue (CheckPackage, 1); + if (!ValueStr) { + PRINT_HII_APP (STRING_TOKEN (STR_GEN_PARAM_INV), ValueStr); + goto Error; + } else { + StartSize = 0; + TrimSpaces ((CHAR16 *)ValueStr); + if (!StrStr (ValueStr, L"://")) { + Context.ServerAddrAndProto = StrnCatGrow ( + &Context.ServerAddrAndProto, + &StartSize, + DEFAULT_HTTP_PROTO, + StrLen (DEFAULT_HTTP_PROTO) + ); + Context.ServerAddrAndProto = StrnCatGrow ( + &Context.ServerAddrAndProto, + &StartSize, + L"://", + StrLen (L"://") + ); + VStr = (CHAR16 *)ValueStr; + } else { + VStr = StrStr (ValueStr, L"://") + StrLen (L"://"); + } + + for (Walker1 = VStr; *Walker1; Walker1++) { + if (*Walker1 == L'/') { + break; + } + } + + if (*Walker1 == L'/') { + ParamOffset = 1; + RemoteFilePath = Walker1; + } + + Context.ServerAddrAndProto = StrnCatGrow ( + &Context.ServerAddrAndProto, + &StartSize, + ValueStr, + StrLen (ValueStr) - StrLen (Walker1) + ); + if (!Context.ServerAddrAndProto) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + } + + if (!RemoteFilePath) { + RemoteFilePath = ShellCommandLineGetRawValue (CheckPackage, 2); + if (!RemoteFilePath) { + // + // If no path given, assume just "/". + // + RemoteFilePath = L"/"; + } + } + + TrimSpaces ((CHAR16 *)RemoteFilePath); + + if (ParamCount == MAX_PARAM_COUNT - ParamOffset) { + mLocalFilePath = ShellCommandLineGetRawValue ( + CheckPackage, + MAX_PARAM_COUNT - 1 - ParamOffset + ); + } else { + Walker = RemoteFilePath + StrLen (RemoteFilePath); + while ((--Walker) >= RemoteFilePath) { + if ((*Walker == L'\\') || + (*Walker == L'/' ) ) { + break; + } + } + + mLocalFilePath = Walker + 1; + } + + if (!StrLen (mLocalFilePath)) { + mLocalFilePath = DEFAULT_HTML_FILE; + } + + InitialSize = 0; + Context.Uri = StrnCatGrow ( + &Context.Uri, + &InitialSize, + RemoteFilePath, + StrLen (RemoteFilePath) + ); + if (!Context.Uri) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + // + // Get the name of the Network Interface Card to be used if any. + // + UserNicName = ShellCommandLineGetValue (CheckPackage, L"-i"); + + ValueStr = ShellCommandLineGetValue (CheckPackage, L"-l"); + if ((ValueStr != NULL) + && (!StringToUint16 ( + ValueStr, + &Context.HttpConfigData.AccessPoint.IPv4Node->LocalPort + ) + )) + { + goto Error; + } + + Context.BufferSize = DEFAULT_BUF_SIZE; + + ValueStr = ShellCommandLineGetValue (CheckPackage, L"-s"); + if (ValueStr != NULL) { + Context.BufferSize = ShellStrToUintn (ValueStr); + if (!Context.BufferSize || Context.BufferSize > MAX_BUF_SIZE) { + PRINT_HII_APP (STRING_TOKEN (STR_GEN_PARAM_INV), ValueStr); + goto Error; + } + } + + ValueStr = ShellCommandLineGetValue (CheckPackage, L"-t"); + if (ValueStr != NULL) { + Context.HttpConfigData.TimeOutMillisec = (UINT32)ShellStrToUintn (ValueStr); + } + + // + // Locate all HTTP Service Binding protocols. + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiManagedNetworkServiceBindingProtocolGuid, + NULL, + &HandleCount, + &Handles + ); + if (EFI_ERROR (Status) || (HandleCount == 0)) { + PRINT_HII (STRING_TOKEN (STR_HTTP_ERR_NO_NIC), NULL); + if (!EFI_ERROR (Status)) { + Status = EFI_NOT_FOUND; + } + + goto Error; + } + + Status = EFI_NOT_FOUND; + + Context.Flags = 0; + if (ShellCommandLineGetFlag (CheckPackage, L"-m")) { + Context.Flags |= DL_FLAG_TIME; + } + + if (ShellCommandLineGetFlag (CheckPackage, L"-k")) { + Context.Flags |= DL_FLAG_KEEP_BAD; + } + + for (NicNumber = 0; + (NicNumber < HandleCount) && (Status != EFI_SUCCESS); + NicNumber++) + { + ControllerHandle = Handles[NicNumber]; + + Status = GetNicName (ControllerHandle, NicNumber, NicName); + if (EFI_ERROR (Status)) { + PRINT_HII (STRING_TOKEN (STR_HTTP_ERR_NIC_NAME), NicNumber, Status); + continue; + } + + if (UserNicName != NULL) { + if (StrCmp (NicName, UserNicName) != 0) { + Status = EFI_NOT_FOUND; + continue; + } + + NicFound = TRUE; + } + + Status = DownloadFile (&Context, ControllerHandle, NicName); + PRINT_HII (STRING_TOKEN (STR_GEN_CRLF), NULL); + + if (EFI_ERROR (Status)) { + PRINT_HII ( + STRING_TOKEN (STR_HTTP_ERR_DOWNLOAD), + RemoteFilePath, + NicName, + Status + ); + // + // If a user aborted the operation, + // do not try another controller. + // + if (Status == EFI_ABORTED) { + goto Error; + } + } + + if (gHttpError) { + // + // This is not related to connection, so no need to repeat with + // another interface. + // + break; + } + } + + if ((UserNicName != NULL) && (!NicFound)) { + PRINT_HII (STRING_TOKEN (STR_HTTP_ERR_NIC_NOT_FOUND), UserNicName); + } + +Error: + ShellCommandLineFreeVarList (CheckPackage); + SHELL_FREE_NON_NULL (Handles); + SHELL_FREE_NON_NULL (Context.ServerAddrAndProto); + SHELL_FREE_NON_NULL (Context.Uri); + + return Status & ~MAX_BIT; +} + +/** + Check and convert the UINT16 option values of the 'http' command + + @param[in] ValueStr Value as an Unicode encoded string + @param[out] Value UINT16 value + + @retval TRUE The value was returned. + @retval FALSE A parsing error occured. +**/ +STATIC +BOOLEAN +StringToUint16 ( + IN CONST CHAR16 *ValueStr, + OUT UINT16 *Value + ) +{ + UINTN Val; + + Val = ShellStrToUintn (ValueStr); + if (Val > MAX_UINT16) { + PRINT_HII_APP (STRING_TOKEN (STR_GEN_PARAM_INV), ValueStr); + return FALSE; + } + + *Value = (UINT16)Val; + return TRUE; +} + +/** + Get the name of the NIC. + + @param[in] ControllerHandle The network physical device handle. + @param[in] NicNumber The network physical device number. + @param[out] NicName Address where to store the NIC name. + The memory area has to be at least + IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH + double byte wide. + + @retval EFI_SUCCESS The name of the NIC was returned. + @retval Others The creation of the child for the Managed + Network Service failed or the opening of + the Managed Network Protocol failed or + the operational parameters for the + Managed Network Protocol could not be + read. +**/ +STATIC +EFI_STATUS +GetNicName ( + IN EFI_HANDLE ControllerHandle, + IN UINTN NicNumber, + OUT CHAR16 *NicName + ) +{ + EFI_STATUS Status; + EFI_HANDLE MnpHandle; + EFI_MANAGED_NETWORK_PROTOCOL *Mnp; + EFI_SIMPLE_NETWORK_MODE SnpMode; + + Status = CreateServiceChildAndOpenProtocol ( + ControllerHandle, + &gEfiManagedNetworkServiceBindingProtocolGuid, + &gEfiManagedNetworkProtocolGuid, + &MnpHandle, + (VOID**)&Mnp + ); + if (EFI_ERROR (Status)) { + goto Error; + } + + Status = Mnp->GetModeData (Mnp, NULL, &SnpMode); + if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) { + goto Error; + } + + UnicodeSPrint ( + NicName, + IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH, + SnpMode.IfType == NET_IFTYPE_ETHERNET ? L"eth%d" : L"unk%d", + NicNumber + ); + + Status = EFI_SUCCESS; + +Error: + + if (MnpHandle != NULL) { + CloseProtocolAndDestroyServiceChild ( + ControllerHandle, + &gEfiManagedNetworkServiceBindingProtocolGuid, + &gEfiManagedNetworkProtocolGuid, + MnpHandle + ); + } + + return Status; +} + +/** + Create a child for the service identified by its service binding protocol GUID + and get from the child the interface of the protocol identified by its GUID. + + @param[in] ControllerHandle Controller handle. + @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the + service to be created. + @param[in] ProtocolGuid GUID of the protocol to be open. + @param[out] ChildHandle Address where the handler of the + created child is returned. NULL is + returned in case of error. + @param[out] Interface Address where a pointer to the + protocol interface is returned in + case of success. + + @retval EFI_SUCCESS The child was created and the protocol opened. + @retval Others Either the creation of the child or the opening + of the protocol failed. +**/ +STATIC +EFI_STATUS +CreateServiceChildAndOpenProtocol ( + IN EFI_HANDLE ControllerHandle, + IN EFI_GUID *ServiceBindingProtocolGuid, + IN EFI_GUID *ProtocolGuid, + OUT EFI_HANDLE *ChildHandle, + OUT VOID **Interface + ) +{ + EFI_STATUS Status; + + *ChildHandle = NULL; + Status = NetLibCreateServiceChild ( + ControllerHandle, + gImageHandle, + ServiceBindingProtocolGuid, + ChildHandle + ); + if (!EFI_ERROR (Status)) { + Status = gBS->OpenProtocol ( + *ChildHandle, + ProtocolGuid, + Interface, + gImageHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + NetLibDestroyServiceChild ( + ControllerHandle, + gImageHandle, + ServiceBindingProtocolGuid, + *ChildHandle + ); + *ChildHandle = NULL; + } + } + + return Status; +} + +/** + Close the protocol identified by its GUID on the child handle of the service + identified by its service binding protocol GUID, then destroy the child + handle. + + @param[in] ControllerHandle Controller handle. + @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the + service to be destroyed. + @param[in] ProtocolGuid GUID of the protocol to be closed. + @param[in] ChildHandle Handle of the child to be destroyed. +**/ +STATIC +VOID +CloseProtocolAndDestroyServiceChild ( + IN EFI_HANDLE ControllerHandle, + IN EFI_GUID *ServiceBindingProtocolGuid, + IN EFI_GUID *ProtocolGuid, + IN EFI_HANDLE ChildHandle + ) +{ + gBS->CloseProtocol ( + ChildHandle, + ProtocolGuid, + gImageHandle, + ControllerHandle + ); + + NetLibDestroyServiceChild ( + ControllerHandle, + gImageHandle, + ServiceBindingProtocolGuid, + ChildHandle + ); +} + +/** + Wait until operation completes. Completion is indicated by + setting of an appropriate variable. + + @param[in] Context A pointer to the HTTP download context. + @param[in, out] CallBackComplete A pointer to the callback completion + variable set by the callback. + + @retval EFI_SUCCESS Callback signalled completion. + @retval EFI_TIMEOUT Timed out waiting for completion. + @retval Others Error waiting for completion. +**/ +STATIC +EFI_STATUS +WaitForCompletion ( + IN HTTP_DOWNLOAD_CONTEXT *Context, + IN OUT BOOLEAN *CallBackComplete + ) +{ + EFI_STATUS Status; + EFI_EVENT WaitEvt; + + Status = EFI_SUCCESS; + + // + // Use a timer to measure timeout. Cannot use Stall here! + // + Status = gBS->CreateEvent ( + EVT_TIMER, + TPL_CALLBACK, + NULL, + NULL, + &WaitEvt + ); + ASSERT_EFI_ERROR (Status); + + if (!EFI_ERROR (Status)) { + Status = gBS->SetTimer ( + WaitEvt, + TimerRelative, + EFI_TIMER_PERIOD_SECONDS (TIMER_MAX_TIMEOUT_S) + ); + + ASSERT_EFI_ERROR (Status); + } + + while (! *CallBackComplete + && (!EFI_ERROR (Status)) + && EFI_ERROR (gBS->CheckEvent (WaitEvt))) + { + Status = Context->Http->Poll (Context->Http); + if (!Context->ContentDownloaded + && CallBackComplete == &gResponseCallbackComplete) + { + // + // An HTTP server may just send a response redirection header. + // In this case, don't wait for the event as + // it might never happen and we waste 10s waiting. + // Note that at this point Response may not has been populated, + // so it needs to be checked first. + // + if (Context->ResponseToken.Message + && Context->ResponseToken.Message->Data.Response + && (NEED_REDIRECTION ( + Context->ResponseToken.Message->Data.Response->StatusCode + ) + )) + { + break; + } + } + } + + gBS->SetTimer (WaitEvt, TimerCancel, 0); + gBS->CloseEvent (WaitEvt); + + if (*CallBackComplete) { + return EFI_SUCCESS; + } + + if (!EFI_ERROR (Status)) { + Status = EFI_TIMEOUT; + } + + return Status; +} + +/** + Generate and send a request to the http server. + + @param[in] Context HTTP download context. + @param[in] DownloadUrl Fully qualified URL to be downloaded. + + @retval EFI_SUCCESS Request has been sent successfully. + @retval EFI_INVALID_PARAMETER Invalid URL. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR If HTTPS is used, this probably + means that TLS support either was not + installed or not configured. + @retval Others Error sending the request. +**/ +STATIC +EFI_STATUS +SendRequest ( + IN HTTP_DOWNLOAD_CONTEXT *Context, + IN CHAR16 *DownloadUrl + ) +{ + EFI_HTTP_REQUEST_DATA RequestData; + EFI_HTTP_HEADER RequestHeader[HdrMax]; + EFI_HTTP_MESSAGE RequestMessage; + EFI_STATUS Status; + CHAR16 *Host; + UINTN StringSize; + + ZeroMem (&RequestData, sizeof (RequestData)); + ZeroMem (&RequestHeader, sizeof (RequestHeader)); + ZeroMem (&RequestMessage, sizeof (RequestMessage)); + ZeroMem (&Context->RequestToken, sizeof (Context->RequestToken)); + + RequestHeader[HdrHost].FieldName = "Host"; + RequestHeader[HdrConn].FieldName = "Connection"; + RequestHeader[HdrAgent].FieldName = "User-Agent"; + + Host = (CHAR16 *)Context->ServerAddrAndProto; + while (*Host != CHAR_NULL && *Host != L'/') { + Host++; + } + + if (*Host == CHAR_NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Get the next slash. + // + Host++; + // + // And now the host name. + // + Host++; + + StringSize = StrLen (Host) + 1; + RequestHeader[HdrHost].FieldValue = AllocatePool (StringSize); + if (!RequestHeader[HdrHost].FieldValue) { + return EFI_OUT_OF_RESOURCES; + } + + UnicodeStrToAsciiStrS ( + Host, + RequestHeader[HdrHost].FieldValue, + StringSize + ); + + RequestHeader[HdrConn].FieldValue = "close"; + RequestHeader[HdrAgent].FieldValue = USER_AGENT_HDR; + RequestMessage.HeaderCount = HdrMax; + + RequestData.Method = HttpMethodGet; + RequestData.Url = DownloadUrl; + + RequestMessage.Data.Request = &RequestData; + RequestMessage.Headers = RequestHeader; + RequestMessage.BodyLength = 0; + RequestMessage.Body = NULL; + Context->RequestToken.Event = NULL; + + // + // Completion callback event to be set when Request completes. + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + RequestCallback, + Context, + &Context->RequestToken.Event + ); + ASSERT_EFI_ERROR (Status); + + Context->RequestToken.Status = EFI_SUCCESS; + Context->RequestToken.Message = &RequestMessage; + gRequestCallbackComplete = FALSE; + Status = Context->Http->Request (Context->Http, &Context->RequestToken); + if (EFI_ERROR (Status)) { + goto Error; + } + + Status = WaitForCompletion (Context, &gRequestCallbackComplete); + if (EFI_ERROR (Status)) { + Context->Http->Cancel (Context->Http, &Context->RequestToken); + } + +Error: + SHELL_FREE_NON_NULL (RequestHeader[HdrHost].FieldValue); + if (Context->RequestToken.Event) { + gBS->CloseEvent (Context->RequestToken.Event); + ZeroMem (&Context->RequestToken, sizeof (Context->RequestToken)); + } + + return Status; +} + +/** + Update the progress of a file download + This procedure is called each time a new HTTP body portion is received. + + @param[in] Context HTTP download context. + @param[in] DownloadLen Portion size, in bytes. + @param[in] Buffer The pointer to the parsed buffer. + + @retval EFI_SUCCESS Portion saved. + @retval Other Error saving the portion. +**/ +STATIC +EFI_STATUS +EFIAPI +SavePortion ( + IN HTTP_DOWNLOAD_CONTEXT *Context, + IN UINTN DownloadLen, + IN CHAR8 *Buffer + ) +{ + CHAR16 Progress[HTTP_PROGRESS_MESSAGE_SIZE]; + UINTN NbOfKb; + UINTN Index; + UINTN LastStep; + UINTN Step; + EFI_STATUS Status; + + LastStep = 0; + Step = 0; + + ShellSetFilePosition (mFileHandle, Context->LastReportedNbOfBytes); + Status = ShellWriteFile (mFileHandle, &DownloadLen, Buffer); + if (EFI_ERROR (Status)) { + if (Context->ContentDownloaded > 0) { + PRINT_HII (STRING_TOKEN (STR_GEN_CRLF), NULL); + } + + PRINT_HII (STRING_TOKEN (STR_HTTP_ERR_WRITE), mLocalFilePath, Status); + return Status; + } + + if (Context->ContentDownloaded == 0) { + ShellPrintEx (-1, -1, L"%s 0 Kb", HTTP_PROGR_FRAME); + } + + Context->ContentDownloaded += DownloadLen; + NbOfKb = Context->ContentDownloaded >> 10; + + Progress[0] = L'\0'; + if (Context->ContentLength) { + LastStep = (Context->LastReportedNbOfBytes * HTTP_PROGRESS_SLIDER_STEPS) / + Context->ContentLength; + Step = (Context->ContentDownloaded * HTTP_PROGRESS_SLIDER_STEPS) / + Context->ContentLength; + } + + Context->LastReportedNbOfBytes = Context->ContentDownloaded; + + if (Step <= LastStep) { + if (!Context->ContentLength) { + // + // Update downloaded size, there is no length info available. + // + ShellPrintEx (-1, -1, L"%s", HTTP_KB); + ShellPrintEx (-1, -1, L"%7d Kb", NbOfKb); + } + + return EFI_SUCCESS; + } + + ShellPrintEx (-1, -1, L"%s", HTTP_PROGRESS_DEL); + + Status = StrCpyS (Progress, HTTP_PROGRESS_MESSAGE_SIZE, HTTP_PROGR_FRAME); + if (EFI_ERROR (Status)) { + return Status; + } + + for (Index = 1; Index < Step; Index++) { + Progress[Index] = L'='; + } + + if (Step) { + Progress[Step] = L'>'; + } + + UnicodeSPrint ( + Progress + (sizeof (HTTP_PROGR_FRAME) / sizeof (CHAR16)) - 1, + sizeof (Progress) - sizeof (HTTP_PROGR_FRAME), + L" %7d Kb", + NbOfKb + ); + + + ShellPrintEx (-1, -1, L"%s", Progress); + + return EFI_SUCCESS; +} + +/** + Replace the original Host and Uri with Host and Uri returned by the + HTTP server in 'Location' header (redirection). + + @param[in] Location A pointer to the 'Location' string + provided by HTTP server. + @param[in] Context A pointer to HTTP download context. + @param[in] DownloadUrl Fully qualified HTTP URL. + + @retval EFI_SUCCESS Host and Uri were successfully set. + @retval EFI_OUT_OF_RESOURCES Error setting Host or Uri. +**/ +STATIC +EFI_STATUS +SetHostURI ( + IN CHAR8 *Location, + IN HTTP_DOWNLOAD_CONTEXT *Context, + IN CHAR16 *DownloadUrl + ) +{ + EFI_STATUS Status; + UINTN StringSize; + UINTN FirstStep; + UINTN Idx; + UINTN Step; + CHAR8 *Walker; + CHAR16 *Temp; + CHAR8 *Tmp; + CHAR16 *Url; + BOOLEAN IsAbEmptyUrl; + + Tmp = NULL; + Url = NULL; + IsAbEmptyUrl = FALSE; + FirstStep = 0; + + StringSize = (AsciiStrSize (Location) * sizeof (CHAR16)); + Url = AllocateZeroPool (StringSize); + if (!Url) { + return EFI_OUT_OF_RESOURCES; + } + + Status = AsciiStrToUnicodeStrS ( + (CONST CHAR8 *)Location, + Url, + StringSize + ); + + if (EFI_ERROR (Status)) { + goto Error; + } + + // + // If an HTTP server redirects to the same location more than once, + // then stop attempts and tell it is not reachable. + // + if (!StrCmp (Url, DownloadUrl)) { + Status = EFI_NO_MAPPING; + goto Error; + } + + if (AsciiStrLen (Location) > 2) { + // + // Some servers return 'Location: //server/resource' + // + IsAbEmptyUrl = (Location[0] == '/') && (Location[1] == '/'); + if (IsAbEmptyUrl) { + // + // Skip first "//" + // + Location += 2; + FirstStep = 1; + } + } + + if (AsciiStrStr (Location, "://") || IsAbEmptyUrl) { + Idx = 0; + Walker = Location; + + for (Step = FirstStep; Step < 2; Step++) { + for (; *Walker != '/' && *Walker != '\0'; Walker++) { + Idx++; + } + + if (!Step) { + // + // Skip "//" + // + Idx += 2; + Walker += 2; + } + } + + Tmp = AllocateZeroPool (Idx + 1); + if (!Tmp) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + CopyMem (Tmp, Location, Idx); + + // + // Location now points to Uri + // + Location += Idx; + StringSize = (Idx + 1) * sizeof (CHAR16); + + SHELL_FREE_NON_NULL (Context->ServerAddrAndProto); + + Temp = AllocateZeroPool (StringSize); + if (!Temp) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + Status = AsciiStrToUnicodeStrS ( + (CONST CHAR8 *)Tmp, + Temp, + StringSize + ); + if (EFI_ERROR (Status)) { + SHELL_FREE_NON_NULL (Temp); + goto Error; + } + + Idx = 0; + if (IsAbEmptyUrl) { + Context->ServerAddrAndProto = StrnCatGrow ( + &Context->ServerAddrAndProto, + &Idx, + L"http://", + StrLen (L"http://") + ); + } + + Context->ServerAddrAndProto = StrnCatGrow ( + &Context->ServerAddrAndProto, + &Idx, + Temp, + StrLen (Temp) + ); + SHELL_FREE_NON_NULL (Temp); + if (!Context->ServerAddrAndProto) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + } + + SHELL_FREE_NON_NULL (Context->Uri); + + StringSize = AsciiStrSize (Location) * sizeof (CHAR16); + Context->Uri = AllocateZeroPool (StringSize); + if (!Context->Uri) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + // + // Now make changes to the Uri part. + // + Status = AsciiStrToUnicodeStrS ( + (CONST CHAR8 *)Location, + Context->Uri, + StringSize + ); +Error: + SHELL_FREE_NON_NULL (Tmp); + SHELL_FREE_NON_NULL (Url); + + return Status; +} + +/** + Message parser callback. + Save a portion of HTTP body. + + @param[in] EventType Type of event. Can be either + OnComplete or OnData. + @param[in] Data A pointer to the buffer with data. + @param[in] Length Data length of this portion. + @param[in] Context A pointer to the HTTP download context. + + @retval EFI_SUCCESS The portion was processed successfully. + @retval Other Error returned by SavePortion. +**/ +STATIC +EFI_STATUS +EFIAPI +ParseMsg ( + IN HTTP_BODY_PARSE_EVENT EventType, + IN CHAR8 *Data, + IN UINTN Length, + IN VOID *Context + ) +{ + if ((Data == NULL) + || (EventType == BodyParseEventOnComplete) + || (Context == NULL)) + { + return EFI_SUCCESS; + } + + return SavePortion (Context, Length, Data); +} + + +/** + Get HTTP server response and collect the whole body as a file. + Set appropriate status in Context (REQ_OK, REQ_REPEAT, REQ_ERROR). + Note that even if HTTP server returns an error code, it might send + the body as well. This body will be collected in the resultant file. + + @param[in] Context A pointer to the HTTP download context. + @param[in] DownloadUrl A pointer to the fully qualified URL to download. + + @retval EFI_SUCCESS Valid file. Body successfully collected. + @retval EFI_HTTP_ERROR Response is a valid HTTP response, but the + HTTP server + indicated an error (HTTP code >= 400). + Response body MAY contain full + HTTP server response. + @retval Others Error getting the reponse from the HTTP server. + Response body is not collected. +**/ +STATIC +EFI_STATUS +GetResponse ( + IN HTTP_DOWNLOAD_CONTEXT *Context, + IN CHAR16 *DownloadUrl + ) +{ + EFI_HTTP_RESPONSE_DATA ResponseData; + EFI_HTTP_MESSAGE ResponseMessage; + EFI_HTTP_HEADER *Header; + EFI_STATUS Status; + VOID *MsgParser; + EFI_TIME StartTime; + EFI_TIME EndTime; + CONST CHAR16 *Desc; + UINTN ElapsedSeconds; + BOOLEAN IsTrunked; + BOOLEAN CanMeasureTime; + + ZeroMem (&ResponseData, sizeof (ResponseData)); + ZeroMem (&ResponseMessage, sizeof (ResponseMessage)); + ZeroMem (&Context->ResponseToken, sizeof (Context->ResponseToken)); + IsTrunked = FALSE; + + ResponseMessage.Body = Context->Buffer; + Context->ResponseToken.Status = EFI_SUCCESS; + Context->ResponseToken.Message = &ResponseMessage; + Context->ContentLength = 0; + Context->Status = REQ_OK; + Status = EFI_SUCCESS; + MsgParser = NULL; + ResponseData.StatusCode = HTTP_STATUS_UNSUPPORTED_STATUS; + ResponseMessage.Data.Response = &ResponseData; + Context->ResponseToken.Event = NULL; + CanMeasureTime = FALSE; + if (Context->Flags & DL_FLAG_TIME) { + ZeroMem (&StartTime, sizeof (StartTime)); + CanMeasureTime = !EFI_ERROR (gRT->GetTime (&StartTime, NULL)); + } + + do { + SHELL_FREE_NON_NULL (ResponseMessage.Headers); + ResponseMessage.HeaderCount = 0; + gResponseCallbackComplete = FALSE; + ResponseMessage.BodyLength = Context->BufferSize; + + if (ShellGetExecutionBreakFlag ()) { + Status = EFI_ABORTED; + break; + } + + if (!Context->ContentDownloaded && !Context->ResponseToken.Event) { + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + ResponseCallback, + Context, + &Context->ResponseToken.Event + ); + ASSERT_EFI_ERROR (Status); + } else { + ResponseMessage.Data.Response = NULL; + } + + if (EFI_ERROR (Status)) { + break; + } + + Status = Context->Http->Response (Context->Http, &Context->ResponseToken); + if (EFI_ERROR (Status)) { + break; + } + + Status = WaitForCompletion (Context, &gResponseCallbackComplete); + if (EFI_ERROR (Status) && ResponseMessage.HeaderCount) { + Status = EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + Context->Http->Cancel (Context->Http, &Context->ResponseToken); + break; + } + + if (!Context->ContentDownloaded) { + if (NEED_REDIRECTION (ResponseData.StatusCode)) { + // + // Need to repeat the request with new Location (server redirected). + // + Context->Status = REQ_NEED_REPEAT; + + Header = HttpFindHeader ( + ResponseMessage.HeaderCount, + ResponseMessage.Headers, + "Location" + ); + if (Header) { + Status = SetHostURI (Header->FieldValue, Context, DownloadUrl); + if (Status == EFI_NO_MAPPING) { + PRINT_HII ( + STRING_TOKEN (STR_HTTP_ERR_STATUSCODE), + Context->ServerAddrAndProto, + L"Recursive HTTP server relocation", + Context->Uri + ); + } + } else { + // + // Bad reply from the server. Server must specify the location. + // Indicate that resource was not found, and no body collected. + // + Status = EFI_NOT_FOUND; + } + + Context->Http->Cancel (Context->Http, &Context->ResponseToken); + break; + } + + // + // Init message-body parser by header information. + // + if (!MsgParser) { + Status = HttpInitMsgParser ( + ResponseMessage.Data.Request->Method, + ResponseData.StatusCode, + ResponseMessage.HeaderCount, + ResponseMessage.Headers, + ParseMsg, + Context, + &MsgParser + ); + if (EFI_ERROR (Status)) { + break; + } + } + + // + // If it is a trunked message, rely on the parser. + // + Header = HttpFindHeader ( + ResponseMessage.HeaderCount, + ResponseMessage.Headers, + "Transfer-Encoding" + ); + IsTrunked = (Header && !AsciiStrCmp (Header->FieldValue, "chunked")); + + HttpGetEntityLength (MsgParser, &Context->ContentLength); + + if (ResponseData.StatusCode >= HTTP_STATUS_400_BAD_REQUEST + && (ResponseData.StatusCode != HTTP_STATUS_308_PERMANENT_REDIRECT)) + { + // + // Server reported an error via Response code. + // Collect the body if any. + // + if (!gHttpError) { + gHttpError = TRUE; + + Desc = ErrStatusDesc[ResponseData.StatusCode - + HTTP_STATUS_400_BAD_REQUEST]; + PRINT_HII ( + STRING_TOKEN (STR_HTTP_ERR_STATUSCODE), + Context->ServerAddrAndProto, + Desc, + Context->Uri + ); + + // + // This gives an RFC HTTP error. + // + Context->Status = ShellStrToUintn (Desc); + Status = ENCODE_ERROR (Context->Status); + } + } + } + + // + // Do NOT try to parse an empty body. + // + if (ResponseMessage.BodyLength || IsTrunked) { + Status = HttpParseMessageBody ( + MsgParser, + ResponseMessage.BodyLength, + ResponseMessage.Body + ); + } + } while (!HttpIsMessageComplete (MsgParser) + && !EFI_ERROR (Status) + && ResponseMessage.BodyLength); + + if (Context->Status != REQ_NEED_REPEAT + && Status == EFI_SUCCESS + && CanMeasureTime) + { + if (!EFI_ERROR (gRT->GetTime (&EndTime, NULL))) { + ElapsedSeconds = EfiTimeToEpoch (&EndTime) - EfiTimeToEpoch (&StartTime); + Print ( + L",%a%Lus\n", + ElapsedSeconds ? " " : " < ", + ElapsedSeconds > 1 ? (UINT64)ElapsedSeconds : 1 + ); + } + } + + SHELL_FREE_NON_NULL (MsgParser); + if (Context->ResponseToken.Event) { + gBS->CloseEvent (Context->ResponseToken.Event); + ZeroMem (&Context->ResponseToken, sizeof (Context->ResponseToken)); + } + + return Status; +} + +/** + Worker function that downloads the data of a file from an HTTP server given + the path of the file and its size. + + @param[in] Context A pointer to the HTTP download context. + @param[in] ControllerHandle The handle of the network interface controller + @param[in] NicName NIC name + + @retval EFI_SUCCESS The file was downloaded. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + #return EFI_HTTP_ERROR The server returned a valid HTTP error. + Examine the mLocalFilePath file + to get error body. + @retval Others The downloading of the file from the server + failed. +**/ +STATIC +EFI_STATUS +DownloadFile ( + IN HTTP_DOWNLOAD_CONTEXT *Context, + IN EFI_HANDLE ControllerHandle, + IN CHAR16 *NicName + ) +{ + EFI_STATUS Status; + CHAR16 *DownloadUrl; + UINTN UrlSize; + EFI_HANDLE HttpChildHandle; + + ASSERT (Context); + if (Context == NULL) { + return EFI_INVALID_PARAMETER; + } + + DownloadUrl = NULL; + HttpChildHandle = NULL; + + Context->Buffer = AllocatePool (Context->BufferSize); + if (Context->Buffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + // + // Open the file. + // + if (!EFI_ERROR (ShellFileExists (mLocalFilePath))) { + ShellDeleteFileByName (mLocalFilePath); + } + + Status = ShellOpenFileByName ( + mLocalFilePath, + &mFileHandle, + EFI_FILE_MODE_CREATE | + EFI_FILE_MODE_WRITE | + EFI_FILE_MODE_READ, + 0 + ); + if (EFI_ERROR (Status)) { + PRINT_HII_APP (STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), mLocalFilePath); + goto ON_EXIT; + } + + do { + SHELL_FREE_NON_NULL (DownloadUrl); + + CLOSE_HTTP_HANDLE (ControllerHandle, HttpChildHandle); + + Status = CreateServiceChildAndOpenProtocol ( + ControllerHandle, + &gEfiHttpServiceBindingProtocolGuid, + &gEfiHttpProtocolGuid, + &HttpChildHandle, + (VOID**)&Context->Http + ); + + if (EFI_ERROR (Status)) { + PRINT_HII (STRING_TOKEN (STR_HTTP_ERR_OPEN_PROTOCOL), NicName, Status); + goto ON_EXIT; + } + + Status = Context->Http->Configure (Context->Http, &Context->HttpConfigData); + if (EFI_ERROR (Status)) { + PRINT_HII (STRING_TOKEN (STR_HTTP_ERR_CONFIGURE), NicName, Status); + goto ON_EXIT; + } + + UrlSize = 0; + DownloadUrl = StrnCatGrow ( + &DownloadUrl, + &UrlSize, + Context->ServerAddrAndProto, + StrLen (Context->ServerAddrAndProto) + ); + if (Context->Uri[0] != L'/') { + DownloadUrl = StrnCatGrow ( + &DownloadUrl, + &UrlSize, + L"/", + StrLen (Context->ServerAddrAndProto) + ); + } + + DownloadUrl = StrnCatGrow ( + &DownloadUrl, + &UrlSize, + Context->Uri, + StrLen (Context->Uri)); + + PRINT_HII (STRING_TOKEN (STR_HTTP_DOWNLOADING), DownloadUrl); + + Status = SendRequest (Context, DownloadUrl); + if (Status) { + goto ON_EXIT; + } + + Status = GetResponse (Context, DownloadUrl); + + if (Status) { + goto ON_EXIT; + } + + } while (Context->Status == REQ_NEED_REPEAT); + + if (Context->Status) { + Status = ENCODE_ERROR (Context->Status); + } + +ON_EXIT: + // + // Close the file. + // + if (mFileHandle != NULL) { + if (EFI_ERROR (Status) && !(Context->Flags & DL_FLAG_KEEP_BAD)) { + ShellDeleteFile (&mFileHandle); + } else { + ShellCloseFile (&mFileHandle); + } + } + + SHELL_FREE_NON_NULL (DownloadUrl); + SHELL_FREE_NON_NULL (Context->Buffer); + + CLOSE_HTTP_HANDLE (ControllerHandle, HttpChildHandle); + + return Status; +} + +/** + Retrive HII package list from ImageHandle and publish to HII database. + + @param[in] ImageHandle The image handle of the process. + + @retval HII handle. +**/ +EFI_HII_HANDLE +InitializeHiiPackage ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + EFI_HII_PACKAGE_LIST_HEADER *PackageList; + EFI_HII_HANDLE HiiHandle; + + // + // Retrieve HII package list from ImageHandle. + // + Status = gBS->OpenProtocol ( + ImageHandle, + &gEfiHiiPackageListProtocolGuid, + (VOID **)&PackageList, + ImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return NULL; + } + + // + // Publish HII package list to HII Database. + // + Status = gHiiDatabase->NewPackageList ( + gHiiDatabase, + PackageList, + NULL, + &HiiHandle + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return NULL; + } + + return HiiHandle; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.h new file mode 100644 index 00000000..c09096af --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.h @@ -0,0 +1,92 @@ +/** @file + Header file for 'http' command functions. + + Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.
+ Copyright (c) 2015, ARM Ltd. All rights reserved.
+ Copyright (c) 2020, Broadcom. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _HTTP_H_ +#define _HTTP_H_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define HTTP_APP_NAME L"http" + +#define REQ_OK 0 +#define REQ_NEED_REPEAT 1 + +// +// Download Flags. +// +#define DL_FLAG_TIME BIT0 // Show elapsed time. +#define DL_FLAG_KEEP_BAD BIT1 // Keep files even if download failed. + +extern EFI_HII_HANDLE mHttpHiiHandle; + +typedef struct { + UINTN ContentDownloaded; + UINTN ContentLength; + UINTN LastReportedNbOfBytes; + UINTN BufferSize; + UINTN Status; + UINTN Flags; + UINT8 *Buffer; + CHAR16 *ServerAddrAndProto; + CHAR16 *Uri; + EFI_HTTP_TOKEN ResponseToken; + EFI_HTTP_TOKEN RequestToken; + EFI_HTTP_PROTOCOL *Http; + EFI_HTTP_CONFIG_DATA HttpConfigData; +} HTTP_DOWNLOAD_CONTEXT; + +/** + Function for 'http' command. + + @param[in] ImageHandle The image handle. + @param[in] SystemTable The system table. + + @retval SHELL_SUCCESS Command completed successfully. + @retval SHELL_INVALID_PARAMETER Command usage error. + @retval SHELL_ABORTED The user aborts the operation. + @retval value Unknown error. +**/ +SHELL_STATUS +RunHttp ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Retrieve HII package list from ImageHandle and publish to HII database. + + @param[in] ImageHandle The image handle of the process. + + @retval HII handle. +**/ +EFI_HII_HANDLE +InitializeHiiPackage ( + IN EFI_HANDLE ImageHandle + ); +#endif // _HTTP_H_ diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.uni b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.uni new file mode 100644 index 00000000..00cf05de --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.uni @@ -0,0 +1,117 @@ +// /** +// +// (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
+// Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+// Copyright (c) 2020, Broadcom. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// Module Name: +// +// Http.uni +// +// Abstract: +// +// String definitions for UEFI Shell HTTP command +// +// +// **/ + +/=# + +#langdef en-US "english" + +#string STR_GEN_TOO_MANY #language en-US "%H%s%N: Too many arguments. Try help http.\r\n" +#string STR_GEN_TOO_FEW #language en-US "%H%s%N: Too few arguments. Try help http.\r\n" +#string STR_GEN_PARAM_INV #language en-US "%H%s%N: Invalid argument - '%H%s%N'. Try help http.\r\n" +#string STR_GEN_PROBLEM #language en-US "%H%s%N: Unknown flag - '%H%s%N'. Try help http.\r\n" +#string STR_GEN_FILE_OPEN_FAIL #language en-US "%H%s%N: Cannot open file - '%H%s%N'\r\n" +#string STR_GEN_CRLF #language en-US "\r\n" + +#string STR_HTTP_ERR_NO_NIC #language en-US "No network interface card found.\r\n" +#string STR_HTTP_ERR_NIC_NAME #language en-US "Failed to get the name of the network interface card number %d - %r\r\n" +#string STR_HTTP_ERR_OPEN_PROTOCOL #language en-US "Unable to open HTTP protocol on '%H%s%N' - %r\r\n" +#string STR_HTTP_ERR_CONFIGURE #language en-US "Unable to configure HTTP protocol on '%H%s%N' - %r\r\n" +#string STR_HTTP_ERR_DOWNLOAD #language en-US "Unable to download the file '%H%s%N' on '%H%s%N' - %r\r\n" +#string STR_HTTP_ERR_WRITE #language en-US "Unable to write into file '%H%s%N' - %r\r\n" +#string STR_HTTP_ERR_NIC_NOT_FOUND #language en-US "Network Interface Card '%H%s%N' not found.\r\n" +#string STR_HTTP_ERR_STATUSCODE #language en-US "\r'%H%s%N' reports '%s' for '%H%s%N' \r\n" +#string STR_HTTP_DOWNLOADING #language en-US "Downloading '%H%s%N'\r\n" + +#string STR_GET_HELP_HTTP #language en-US "" +".TH http 0 "Download a file from HTTP server."\r\n" +".SH NAME\r\n" +"Download a file from HTTP server.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"HTTP [-i interface] [-l port] [-t timeout] [-s size] [-m] [-k]\r\n" +" [localfilepath]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -i interface - Specifies an adapter name, i.e., eth0.\r\n" +" -k Keep the downloaded file even if there was an error.\r\n" +" If this parameter is not used, the file will be deleted.\r\n" +" -l port - Specifies the local port number. Default value is 0\r\n" +" and the port number is automatically assigned.\r\n" +" -m Measure and report download time (in seconds). \r\n" +" -s size The size of the download buffer for a chunk, in bytes.\r\n" +" Default is 32K. Note that larger buffer does not imply\r\n" +" better speed.\r\n" +" -t timeout - The number of seconds to wait for completion of\r\n" +" requests and responses. Default is 0 which is 'automatic'.\r\n" +" %HURL%N\r\n" +" Two types of providing of URLs are supported:\r\n" +" 1. tftp-like, where host and http_uri are separate parameters\r\n" +" (example: host /host_uri), and\r\n\" +" 2. wget-like, where host and host_uri is one parameter.\r\n" +" (example: host/host_uri)\r\n" +"\r\n" +" host - Specifies HTTP Server address.\r\n + Can be either IPv4 address or 'http (or https)://addr'\r\n + Can use addresses resolvable by DNS as well. \r\n + Port can be specified after ':' if needed. \r\n + By default port 80 is used.\r\n" +" http_uri - HTTP server URI to download the file.\r\n" +"\r\n" +" localfilepath - Local destination file path.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. The HTTP command allows geting of the file specified by its 'http_uri'\r\n" +" path from the HTTP server specified by its 'host' IPv4 address. If the\r\n" +" optional 'localfilepath' parameter is provided, the downloaded file is\r\n" +" stored locally using the provided file path. If the local file path is\r\n" +" not specified, the file is stored in the current directory using the file\r\n" +" server's name.\r\n" +" 2. Before using the HTTP command, the network interface intended to be\r\n" +" used to retrieve the file must be configured. This configuration may be\r\n" +" done by means of the 'ifconfig' command.\r\n" +" 3. If a network interface is defined with the '-i' option then only this\r\n" +" interface will be used to retrieve the remote file. Otherwise, all network\r\n" +" interfaces are tried in the order they have been discovered during the\r\n" +" DXE phase.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To get the file "dir1/file1.dat" from the HTTP server 192.168.1.1, port 8080, and\r\n" +" store it as file2.dat in the current directory (use tftp-like URL format) :\r\n" +" fs0:\> http 192.168.1.1:8080 dir1/file1.dat file2.dat\r\n" +" * To get the file /image.bin via HTTPS from server 192.168.1.1 at port 443 \r\n" +" (default HTTPS port), and store it in the current directory: \r\n" +" fs0:\> http https://192.168.1.1 image.bin\r\n" +" To get an index file from http://google.com and place it into the \r\n" +" current directory:\r\n" +" fs0:\> http google.com index.html\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_INVALID_PARAMETER One of the passed-in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" +" HTTP_ERROR No EFI errors, but the server reported a status code\r\n" +" which should be treated as an error. If an error body sent\r\n" +" by the server, and -k parameter is on command line, +" the file wil be saved either as localfilepath filename,\r\n" +" or as an URI name in the current directory.\r\n" +" If '/' is at the end of the URL, and no locafilepath filename\r\n" +" is given on the command line, the file will be retrieved as\r\n" +" index.html.\r\n" diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.c new file mode 100644 index 00000000..b262e463 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.c @@ -0,0 +1,61 @@ +/** @file + Entrypoint of "http" shell standalone application. + + Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.
+ Copyright (c) 2015, ARM Ltd. All rights reserved.
+ Copyright (c) 2020, Broadcom. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "Http.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_GET_HELP_HTTP); + +/** + Entry point of Http standalone application. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. + + @retval EFI_SUCCESS Http command is executed sucessfully. + @retval EFI_ABORTED HII package was failed to initialize. + @retval others Other errors when executing http command. +**/ +EFI_STATUS +EFIAPI +HttpAppInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + + mHttpHiiHandle = InitializeHiiPackage (ImageHandle); + if (mHttpHiiHandle == NULL) { + return EFI_ABORTED; + } + + Status = EFI_SUCCESS; + + ShellStatus = RunHttp (ImageHandle, SystemTable); + + HiiRemovePackages (mHttpHiiHandle); + + if (Status != SHELL_SUCCESS) { + Status = ENCODE_ERROR (ShellStatus); + } + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.inf new file mode 100644 index 00000000..bdea1fc1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.inf @@ -0,0 +1,57 @@ +## @file +# Provides Shell 'http' standalone application. +# +# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.
+# Copyright (c) 2015, ARM Ltd. All rights reserved.
+# Copyright (c) 2020, Broadcom. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = http + FILE_GUID = 56B00FB7-91D2-869B-CE5C-26CD1A89C73C + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = HttpAppInitialize +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +[Sources.common] + Http.c + HttpApp.c + Http.h + Http.uni + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + NetworkPkg/NetworkPkg.dec + ShellPkg/ShellPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + FileHandleLib + HiiLib + HttpLib + MemoryAllocationLib + NetLib + ShellLib + UefiApplicationEntryPoint + UefiBootServicesTableLib + UefiHiiServicesLib + UefiLib + UefiRuntimeServicesTableLib + +[Protocols] + gEfiHiiPackageListProtocolGuid ## CONSUMES + gEfiHttpProtocolGuid ## CONSUMES + gEfiHttpServiceBindingProtocolGuid ## CONSUMES + gEfiManagedNetworkServiceBindingProtocolGuid ## CONSUMES diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand.c new file mode 100644 index 00000000..5245cba3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand.c @@ -0,0 +1,137 @@ +/** @file + Produce "http" shell dynamic command. + + Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.
+ Copyright (c) 2015, ARM Ltd. All rights reserved.
+ Copyright (c) 2020, Broadcom. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include +#include "Http.h" + +/** + This is the shell command handler function pointer callback type. This + function handles the command when it is invoked in the shell. + + @param[in] This The instance of the + EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL. + @param[in] SystemTable The pointer to the system table. + @param[in] ShellParameters The parameters associated with the command. + @param[in] Shell The instance of the shell protocol used in + the context of processing this command. + + @return EFI_SUCCESS the operation was sucessful + @return other the operation failed. +**/ +SHELL_STATUS +EFIAPI +HttpCommandHandler ( + IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This, + IN EFI_SYSTEM_TABLE *SystemTable, + IN EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters, + IN EFI_SHELL_PROTOCOL *Shell + ) +{ + gEfiShellParametersProtocol = ShellParameters; + gEfiShellProtocol = Shell; + + return RunHttp (gImageHandle, SystemTable); +} + +/** + This is the command help handler function pointer callback type. This + function is responsible for displaying help information for the associated + command. + + @param[in] This The instance of the EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL. + @param[in] Language The pointer to the language string to use. + + @return string Pool allocated help string, must be freed by caller +**/ +CHAR16 * +EFIAPI +HttpCommandGetHelp ( + IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This, + IN CONST CHAR8 *Language + ) +{ + return HiiGetString ( + mHttpHiiHandle, + STRING_TOKEN (STR_GET_HELP_HTTP), + Language + ); +} + +EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL mHttpDynamicCommand = { + HTTP_APP_NAME, + HttpCommandHandler, + HttpCommandGetHelp +}; + +/** + Entry point of Http Dynamic Command. + + Produce the DynamicCommand protocol to handle "http" command. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. + + @retval EFI_SUCCESS Http command is executed sucessfully. + @retval EFI_ABORTED HII package was failed to initialize. + @retval others Other errors when executing http command. +**/ +EFI_STATUS +EFIAPI +HttpCommandInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + mHttpHiiHandle = InitializeHiiPackage (ImageHandle); + if (mHttpHiiHandle == NULL) { + return EFI_ABORTED; + } + + Status = gBS->InstallProtocolInterface ( + &ImageHandle, + &gEfiShellDynamicCommandProtocolGuid, + EFI_NATIVE_INTERFACE, + &mHttpDynamicCommand + ); + ASSERT_EFI_ERROR (Status); + return Status; +} + +/** + Http driver unload handler. + + @param ImageHandle The image handle of the process. + + @retval EFI_SUCCESS The image is unloaded. + @retval Others Failed to unload the image. +**/ +EFI_STATUS +EFIAPI +HttpUnload ( + IN EFI_HANDLE ImageHandle +) +{ + EFI_STATUS Status; + + Status = gBS->UninstallProtocolInterface ( + ImageHandle, + &gEfiShellDynamicCommandProtocolGuid, + &mHttpDynamicCommand + ); + if (EFI_ERROR (Status)) { + return Status; + } + + HiiRemovePackages (mHttpHiiHandle); + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand.inf new file mode 100644 index 00000000..2621bcb7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand.inf @@ -0,0 +1,62 @@ +## @file +# Provides Shell 'http' dynamic command. +# +# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.
+# Copyright (c) 2015, ARM Ltd. All rights reserved.
+# Copyright (c) 2020, Broadcom. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = httpDynamicCommand + FILE_GUID = 19618BCE-55AE-09C6-37E9-4CE04084C7A1 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = HttpCommandInitialize + UNLOAD_IMAGE = HttpUnload +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +[Sources.common] + Http.c + HttpDynamicCommand.c + Http.h + Http.uni + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + NetworkPkg/NetworkPkg.dec + ShellPkg/ShellPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + FileHandleLib + HiiLib + HttpLib + MemoryAllocationLib + NetLib + ShellLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiHiiServicesLib + UefiLib + UefiRuntimeServicesTableLib + +[Protocols] + gEfiHiiPackageListProtocolGuid ## CONSUMES + gEfiHttpProtocolGuid ## CONSUMES + gEfiHttpServiceBindingProtocolGuid ## CONSUMES + gEfiManagedNetworkServiceBindingProtocolGuid ## CONSUMES + gEfiShellDynamicCommandProtocolGuid ## PRODUCES + +[DEPEX] + TRUE diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.c new file mode 100644 index 00000000..589c227d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.c @@ -0,0 +1,1129 @@ +/** @file + The implementation for the 'tftp' Shell command. + + Copyright (c) 2015, ARM Ltd. All rights reserved.
+ Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "Tftp.h" + +#define IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH 32 +EFI_HII_HANDLE mTftpHiiHandle; + +/* + Constant strings and definitions related to the message indicating the amount of + progress in the downloading of a TFTP file. +*/ + +// Frame for the progression slider +STATIC CONST CHAR16 mTftpProgressFrame[] = L"[ ]"; + +// Number of steps in the progression slider +#define TFTP_PROGRESS_SLIDER_STEPS ((sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 3) + +// Size in number of characters plus one (final zero) of the message to +// indicate the progress of a TFTP download. The format is "[(progress slider: +// 40 characters)] (nb of KBytes downloaded so far: 7 characters) Kb". There +// are thus the number of characters in mTftpProgressFrame[] plus 11 characters +// (2 // spaces, "Kb" and seven characters for the number of KBytes). +#define TFTP_PROGRESS_MESSAGE_SIZE ((sizeof (mTftpProgressFrame) / sizeof (CHAR16)) + 12) + +// String to delete the TFTP progress message to be able to update it : +// (TFTP_PROGRESS_MESSAGE_SIZE-1) '\b' +STATIC CONST CHAR16 mTftpProgressDelete[] = L"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"; + +// Local File Handle +SHELL_FILE_HANDLE mFileHandle; + +// Path of the local file, Unicode encoded +CONST CHAR16 *mLocalFilePath; + +/** + Check and convert the UINT16 option values of the 'tftp' command + + @param[in] ValueStr Value as an Unicode encoded string + @param[out] Value UINT16 value + + @return TRUE The value was returned. + @return FALSE A parsing error occurred. +**/ +STATIC +BOOLEAN +StringToUint16 ( + IN CONST CHAR16 *ValueStr, + OUT UINT16 *Value + ); + +/** + Get the name of the NIC. + + @param[in] ControllerHandle The network physical device handle. + @param[in] NicNumber The network physical device number. + @param[out] NicName Address where to store the NIC name. + The memory area has to be at least + IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH + double byte wide. + + @return EFI_SUCCESS The name of the NIC was returned. + @return Others The creation of the child for the Managed + Network Service failed or the opening of + the Managed Network Protocol failed or + the operational parameters for the + Managed Network Protocol could not be + read. +**/ +STATIC +EFI_STATUS +GetNicName ( + IN EFI_HANDLE ControllerHandle, + IN UINTN NicNumber, + OUT CHAR16 *NicName + ); + +/** + Create a child for the service identified by its service binding protocol GUID + and get from the child the interface of the protocol identified by its GUID. + + @param[in] ControllerHandle Controller handle. + @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the + service to be created. + @param[in] ProtocolGuid GUID of the protocol to be open. + @param[out] ChildHandle Address where the handler of the + created child is returned. NULL is + returned in case of error. + @param[out] Interface Address where a pointer to the + protocol interface is returned in + case of success. + + @return EFI_SUCCESS The child was created and the protocol opened. + @return Others Either the creation of the child or the opening + of the protocol failed. +**/ +STATIC +EFI_STATUS +CreateServiceChildAndOpenProtocol ( + IN EFI_HANDLE ControllerHandle, + IN EFI_GUID *ServiceBindingProtocolGuid, + IN EFI_GUID *ProtocolGuid, + OUT EFI_HANDLE *ChildHandle, + OUT VOID **Interface + ); + +/** + Close the protocol identified by its GUID on the child handle of the service + identified by its service binding protocol GUID, then destroy the child + handle. + + @param[in] ControllerHandle Controller handle. + @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the + service to be destroyed. + @param[in] ProtocolGuid GUID of the protocol to be closed. + @param[in] ChildHandle Handle of the child to be destroyed. + +**/ +STATIC +VOID +CloseProtocolAndDestroyServiceChild ( + IN EFI_HANDLE ControllerHandle, + IN EFI_GUID *ServiceBindingProtocolGuid, + IN EFI_GUID *ProtocolGuid, + IN EFI_HANDLE ChildHandle + ); + +/** + Worker function that gets the size in numbers of bytes of a file from a TFTP + server before to download the file. + + @param[in] Mtftp4 MTFTP4 protocol interface + @param[in] FilePath Path of the file, ASCII encoded + @param[out] FileSize Address where to store the file size in number of + bytes. + + @retval EFI_SUCCESS The size of the file was returned. + @retval EFI_UNSUPPORTED The server does not support the "tsize" option. + @retval Others Error when retrieving the information from the server + (see EFI_MTFTP4_PROTOCOL.GetInfo() status codes) + or error when parsing the response of the server. +**/ +STATIC +EFI_STATUS +GetFileSize ( + IN EFI_MTFTP4_PROTOCOL *Mtftp4, + IN CONST CHAR8 *FilePath, + OUT UINTN *FileSize + ); + +/** + Worker function that download the data of a file from a TFTP server given + the path of the file and its size. + + @param[in] Mtftp4 MTFTP4 protocol interface + @param[in] FilePath Path of the file, Unicode encoded + @param[in] AsciiFilePath Path of the file, ASCII encoded + @param[in] FileSize Size of the file in number of bytes + @param[in] BlockSize Value of the TFTP blksize option + @param[in] WindowSize Value of the TFTP window size option + + @retval EFI_SUCCESS The file was downloaded. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval Others The downloading of the file from the server failed + (see EFI_MTFTP4_PROTOCOL.ReadFile() status codes). + +**/ +STATIC +EFI_STATUS +DownloadFile ( + IN EFI_MTFTP4_PROTOCOL *Mtftp4, + IN CONST CHAR16 *FilePath, + IN CONST CHAR8 *AsciiFilePath, + IN UINTN FileSize, + IN UINT16 BlockSize, + IN UINT16 WindowSize + ); + +/** + Update the progress of a file download + This procedure is called each time a new TFTP packet is received. + + @param[in] This MTFTP4 protocol interface + @param[in] Token Parameters for the download of the file + @param[in] PacketLen Length of the packet + @param[in] Packet Address of the packet + + @retval EFI_SUCCESS All packets are accepted. + +**/ +STATIC +EFI_STATUS +EFIAPI +CheckPacket ( + IN EFI_MTFTP4_PROTOCOL *This, + IN EFI_MTFTP4_TOKEN *Token, + IN UINT16 PacketLen, + IN EFI_MTFTP4_PACKET *Packet + ); + +EFI_MTFTP4_CONFIG_DATA DefaultMtftp4ConfigData = { + TRUE, // Use default setting + { { 0, 0, 0, 0 } }, // StationIp - Not relevant as UseDefaultSetting=TRUE + { { 0, 0, 0, 0 } }, // SubnetMask - Not relevant as UseDefaultSetting=TRUE + 0, // LocalPort - Automatically assigned port number. + { { 0, 0, 0, 0 } }, // GatewayIp - Not relevant as UseDefaultSetting=TRUE + { { 0, 0, 0, 0 } }, // ServerIp - Not known yet + 69, // InitialServerPort - Standard TFTP server port + 6, // TryCount - The number of times to transmit request packets and wait for a response. + 4 // TimeoutValue - Retransmission timeout in seconds. +}; + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-i", TypeValue}, + {L"-l", TypeValue}, + {L"-r", TypeValue}, + {L"-c", TypeValue}, + {L"-t", TypeValue}, + {L"-s", TypeValue}, + {L"-w", TypeValue}, + {NULL , TypeMax} + }; + +/// +/// The default block size (512) of tftp is defined in the RFC1350. +/// +#define MTFTP_DEFAULT_BLKSIZE 512 +/// +/// The valid range of block size option is defined in the RFC2348. +/// +#define MTFTP_MIN_BLKSIZE 8 +#define MTFTP_MAX_BLKSIZE 65464 +/// +/// The default windowsize (1) of tftp. +/// +#define MTFTP_DEFAULT_WINDOWSIZE 1 +/// +/// The valid range of window size option. +/// Note that: RFC 7440 does not mention max window size value, but for the +/// stability reason, the value is limited to 64. +/// +#define MTFTP_MIN_WINDOWSIZE 1 +#define MTFTP_MAX_WINDOWSIZE 64 + +/** + Function for 'tftp' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). + + @return SHELL_SUCCESS The 'tftp' command completed successfully. + @return SHELL_ABORTED The Shell Library initialization failed. + @return SHELL_INVALID_PARAMETER At least one of the command's arguments is + not valid. + @return SHELL_OUT_OF_RESOURCES A memory allocation failed. + @return SHELL_NOT_FOUND Network Interface Card not found or server + error or file error. + +**/ +SHELL_STATUS +RunTftp ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + SHELL_STATUS ShellStatus; + EFI_STATUS Status; + LIST_ENTRY *CheckPackage; + CHAR16 *ProblemParam; + UINTN ParamCount; + CONST CHAR16 *UserNicName; + BOOLEAN NicFound; + CONST CHAR16 *ValueStr; + CONST CHAR16 *RemoteFilePath; + CHAR8 *AsciiRemoteFilePath; + UINTN FilePathSize; + CONST CHAR16 *Walker; + EFI_MTFTP4_CONFIG_DATA Mtftp4ConfigData; + EFI_HANDLE *Handles; + UINTN HandleCount; + UINTN NicNumber; + CHAR16 NicName[IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH]; + EFI_HANDLE ControllerHandle; + EFI_HANDLE Mtftp4ChildHandle; + EFI_MTFTP4_PROTOCOL *Mtftp4; + UINTN FileSize; + UINT16 BlockSize; + UINT16 WindowSize; + + ShellStatus = SHELL_INVALID_PARAMETER; + ProblemParam = NULL; + NicFound = FALSE; + AsciiRemoteFilePath = NULL; + Handles = NULL; + FileSize = 0; + BlockSize = MTFTP_DEFAULT_BLKSIZE; + WindowSize = MTFTP_DEFAULT_WINDOWSIZE; + + // + // Initialize the Shell library (we must be in non-auto-init...) + // + Status = ShellInitialize (); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return SHELL_ABORTED; + } + + // + // Parse the command line. + // + Status = ShellCommandLineParse (ParamList, &CheckPackage, &ProblemParam, TRUE); + if (EFI_ERROR (Status)) { + if ((Status == EFI_VOLUME_CORRUPTED) && + (ProblemParam != NULL) ) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), mTftpHiiHandle, + L"tftp", ProblemParam + ); + FreePool (ProblemParam); + } else { + ASSERT (FALSE); + } + goto Error; + } + + // + // Check the number of parameters + // + ParamCount = ShellCommandLineGetCount (CheckPackage); + if (ParamCount > 4) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), + mTftpHiiHandle, L"tftp" + ); + goto Error; + } + if (ParamCount < 3) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), + mTftpHiiHandle, L"tftp" + ); + goto Error; + } + + CopyMem (&Mtftp4ConfigData, &DefaultMtftp4ConfigData, sizeof (EFI_MTFTP4_CONFIG_DATA)); + + // + // Check the host IPv4 address + // + ValueStr = ShellCommandLineGetRawValue (CheckPackage, 1); + Status = NetLibStrToIp4 (ValueStr, &Mtftp4ConfigData.ServerIp); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), + mTftpHiiHandle, L"tftp", ValueStr + ); + goto Error; + } + + RemoteFilePath = ShellCommandLineGetRawValue (CheckPackage, 2); + ASSERT(RemoteFilePath != NULL); + FilePathSize = StrLen (RemoteFilePath) + 1; + AsciiRemoteFilePath = AllocatePool (FilePathSize); + if (AsciiRemoteFilePath == NULL) { + ShellStatus = SHELL_OUT_OF_RESOURCES; + goto Error; + } + UnicodeStrToAsciiStrS (RemoteFilePath, AsciiRemoteFilePath, FilePathSize); + + if (ParamCount == 4) { + mLocalFilePath = ShellCommandLineGetRawValue (CheckPackage, 3); + } else { + Walker = RemoteFilePath + StrLen (RemoteFilePath); + while ((--Walker) >= RemoteFilePath) { + if ((*Walker == L'\\') || + (*Walker == L'/' ) ) { + break; + } + } + mLocalFilePath = Walker + 1; + } + + // + // Get the name of the Network Interface Card to be used if any. + // + UserNicName = ShellCommandLineGetValue (CheckPackage, L"-i"); + + ValueStr = ShellCommandLineGetValue (CheckPackage, L"-l"); + if (ValueStr != NULL) { + if (!StringToUint16 (ValueStr, &Mtftp4ConfigData.LocalPort)) { + goto Error; + } + } + + ValueStr = ShellCommandLineGetValue (CheckPackage, L"-r"); + if (ValueStr != NULL) { + if (!StringToUint16 (ValueStr, &Mtftp4ConfigData.InitialServerPort)) { + goto Error; + } + } + + ValueStr = ShellCommandLineGetValue (CheckPackage, L"-c"); + if (ValueStr != NULL) { + if (!StringToUint16 (ValueStr, &Mtftp4ConfigData.TryCount)) { + goto Error; + } + + if (Mtftp4ConfigData.TryCount == 0) { + Mtftp4ConfigData.TryCount = 6; + } + } + + ValueStr = ShellCommandLineGetValue (CheckPackage, L"-t"); + if (ValueStr != NULL) { + if (!StringToUint16 (ValueStr, &Mtftp4ConfigData.TimeoutValue)) { + goto Error; + } + if (Mtftp4ConfigData.TimeoutValue == 0) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), + mTftpHiiHandle, L"tftp", ValueStr + ); + goto Error; + } + } + + ValueStr = ShellCommandLineGetValue (CheckPackage, L"-s"); + if (ValueStr != NULL) { + if (!StringToUint16 (ValueStr, &BlockSize)) { + goto Error; + } + if (BlockSize < MTFTP_MIN_BLKSIZE || BlockSize > MTFTP_MAX_BLKSIZE) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), + mTftpHiiHandle, L"tftp", ValueStr + ); + goto Error; + } + } + + ValueStr = ShellCommandLineGetValue (CheckPackage, L"-w"); + if (ValueStr != NULL) { + if (!StringToUint16 (ValueStr, &WindowSize)) { + goto Error; + } + if (WindowSize < MTFTP_MIN_WINDOWSIZE || WindowSize > MTFTP_MAX_WINDOWSIZE) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), + mTftpHiiHandle, L"tftp", ValueStr + ); + goto Error; + } + } + + // + // Locate all MTFTP4 Service Binding protocols + // + ShellStatus = SHELL_NOT_FOUND; + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiManagedNetworkServiceBindingProtocolGuid, + NULL, + &HandleCount, + &Handles + ); + if (EFI_ERROR (Status) || (HandleCount == 0)) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_NO_NIC), + mTftpHiiHandle + ); + goto Error; + } + + for (NicNumber = 0; + (NicNumber < HandleCount) && (ShellStatus != SHELL_SUCCESS); + NicNumber++) { + ControllerHandle = Handles[NicNumber]; + + Status = GetNicName (ControllerHandle, NicNumber, NicName); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_NIC_NAME), + mTftpHiiHandle, NicNumber, Status + ); + continue; + } + + if (UserNicName != NULL) { + if (StrCmp (NicName, UserNicName) != 0) { + continue; + } + NicFound = TRUE; + } + + Status = CreateServiceChildAndOpenProtocol ( + ControllerHandle, + &gEfiMtftp4ServiceBindingProtocolGuid, + &gEfiMtftp4ProtocolGuid, + &Mtftp4ChildHandle, + (VOID**)&Mtftp4 + ); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_OPEN_PROTOCOL), + mTftpHiiHandle, NicName, Status + ); + continue; + } + + Status = Mtftp4->Configure (Mtftp4, &Mtftp4ConfigData); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_CONFIGURE), + mTftpHiiHandle, NicName, Status + ); + goto NextHandle; + } + + Status = GetFileSize (Mtftp4, AsciiRemoteFilePath, &FileSize); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_FILE_SIZE), + mTftpHiiHandle, RemoteFilePath, NicName, Status + ); + goto NextHandle; + } + + Status = DownloadFile (Mtftp4, RemoteFilePath, AsciiRemoteFilePath, FileSize, BlockSize, WindowSize); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_DOWNLOAD), + mTftpHiiHandle, RemoteFilePath, NicName, Status + ); + goto NextHandle; + } + + ShellStatus = SHELL_SUCCESS; + + NextHandle: + + CloseProtocolAndDestroyServiceChild ( + ControllerHandle, + &gEfiMtftp4ServiceBindingProtocolGuid, + &gEfiMtftp4ProtocolGuid, + Mtftp4ChildHandle + ); + } + + if ((UserNicName != NULL) && (!NicFound)) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_NIC_NOT_FOUND), + mTftpHiiHandle, UserNicName + ); + } + + Error: + + ShellCommandLineFreeVarList (CheckPackage); + if (AsciiRemoteFilePath != NULL) { + FreePool (AsciiRemoteFilePath); + } + if (Handles != NULL) { + FreePool (Handles); + } + + if ((ShellStatus != SHELL_SUCCESS) && (EFI_ERROR(Status))) { + ShellStatus = Status & ~MAX_BIT; + } + + return ShellStatus; +} + +/** + Check and convert the UINT16 option values of the 'tftp' command + + @param[in] ValueStr Value as an Unicode encoded string + @param[out] Value UINT16 value + + @return TRUE The value was returned. + @return FALSE A parsing error occurred. +**/ +STATIC +BOOLEAN +StringToUint16 ( + IN CONST CHAR16 *ValueStr, + OUT UINT16 *Value + ) +{ + UINTN Val; + + Val = ShellStrToUintn (ValueStr); + if (Val > MAX_UINT16) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), + mTftpHiiHandle, L"tftp", ValueStr + ); + return FALSE; + } + + *Value = (UINT16)Val; + return TRUE; +} + +/** + Get the name of the NIC. + + @param[in] ControllerHandle The network physical device handle. + @param[in] NicNumber The network physical device number. + @param[out] NicName Address where to store the NIC name. + The memory area has to be at least + IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH + double byte wide. + + @return EFI_SUCCESS The name of the NIC was returned. + @return Others The creation of the child for the Managed + Network Service failed or the opening of + the Managed Network Protocol failed or + the operational parameters for the + Managed Network Protocol could not be + read. +**/ +STATIC +EFI_STATUS +GetNicName ( + IN EFI_HANDLE ControllerHandle, + IN UINTN NicNumber, + OUT CHAR16 *NicName + ) +{ + EFI_STATUS Status; + EFI_HANDLE MnpHandle; + EFI_MANAGED_NETWORK_PROTOCOL *Mnp; + EFI_SIMPLE_NETWORK_MODE SnpMode; + + Status = CreateServiceChildAndOpenProtocol ( + ControllerHandle, + &gEfiManagedNetworkServiceBindingProtocolGuid, + &gEfiManagedNetworkProtocolGuid, + &MnpHandle, + (VOID**)&Mnp + ); + if (EFI_ERROR (Status)) { + goto Error; + } + + Status = Mnp->GetModeData (Mnp, NULL, &SnpMode); + if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) { + goto Error; + } + + UnicodeSPrint ( + NicName, + IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH, + SnpMode.IfType == NET_IFTYPE_ETHERNET ? + L"eth%d" : + L"unk%d" , + NicNumber + ); + + Status = EFI_SUCCESS; + +Error: + + if (MnpHandle != NULL) { + CloseProtocolAndDestroyServiceChild ( + ControllerHandle, + &gEfiManagedNetworkServiceBindingProtocolGuid, + &gEfiManagedNetworkProtocolGuid, + MnpHandle + ); + } + + return Status; +} + +/** + Create a child for the service identified by its service binding protocol GUID + and get from the child the interface of the protocol identified by its GUID. + + @param[in] ControllerHandle Controller handle. + @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the + service to be created. + @param[in] ProtocolGuid GUID of the protocol to be open. + @param[out] ChildHandle Address where the handler of the + created child is returned. NULL is + returned in case of error. + @param[out] Interface Address where a pointer to the + protocol interface is returned in + case of success. + + @return EFI_SUCCESS The child was created and the protocol opened. + @return Others Either the creation of the child or the opening + of the protocol failed. +**/ +STATIC +EFI_STATUS +CreateServiceChildAndOpenProtocol ( + IN EFI_HANDLE ControllerHandle, + IN EFI_GUID *ServiceBindingProtocolGuid, + IN EFI_GUID *ProtocolGuid, + OUT EFI_HANDLE *ChildHandle, + OUT VOID **Interface + ) +{ + EFI_STATUS Status; + + *ChildHandle = NULL; + Status = NetLibCreateServiceChild ( + ControllerHandle, + gImageHandle, + ServiceBindingProtocolGuid, + ChildHandle + ); + if (!EFI_ERROR (Status)) { + Status = gBS->OpenProtocol ( + *ChildHandle, + ProtocolGuid, + Interface, + gImageHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + NetLibDestroyServiceChild ( + ControllerHandle, + gImageHandle, + ServiceBindingProtocolGuid, + *ChildHandle + ); + *ChildHandle = NULL; + } + } + + return Status; +} + +/** + Close the protocol identified by its GUID on the child handle of the service + identified by its service binding protocol GUID, then destroy the child + handle. + + @param[in] ControllerHandle Controller handle. + @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the + service to be destroyed. + @param[in] ProtocolGuid GUID of the protocol to be closed. + @param[in] ChildHandle Handle of the child to be destroyed. + +**/ +STATIC +VOID +CloseProtocolAndDestroyServiceChild ( + IN EFI_HANDLE ControllerHandle, + IN EFI_GUID *ServiceBindingProtocolGuid, + IN EFI_GUID *ProtocolGuid, + IN EFI_HANDLE ChildHandle + ) +{ + gBS->CloseProtocol ( + ChildHandle, + ProtocolGuid, + gImageHandle, + ControllerHandle + ); + + NetLibDestroyServiceChild ( + ControllerHandle, + gImageHandle, + ServiceBindingProtocolGuid, + ChildHandle + ); +} + +/** + Worker function that gets the size in numbers of bytes of a file from a TFTP + server before to download the file. + + @param[in] Mtftp4 MTFTP4 protocol interface + @param[in] FilePath Path of the file, ASCII encoded + @param[out] FileSize Address where to store the file size in number of + bytes. + + @retval EFI_SUCCESS The size of the file was returned. + @retval EFI_UNSUPPORTED The server does not support the "tsize" option. + @retval Others Error when retrieving the information from the server + (see EFI_MTFTP4_PROTOCOL.GetInfo() status codes) + or error when parsing the response of the server. +**/ +STATIC +EFI_STATUS +GetFileSize ( + IN EFI_MTFTP4_PROTOCOL *Mtftp4, + IN CONST CHAR8 *FilePath, + OUT UINTN *FileSize + ) +{ + EFI_STATUS Status; + EFI_MTFTP4_OPTION ReqOpt[1]; + EFI_MTFTP4_PACKET *Packet; + UINT32 PktLen; + EFI_MTFTP4_OPTION *TableOfOptions; + EFI_MTFTP4_OPTION *Option; + UINT32 OptCnt; + UINT8 OptBuf[128]; + + ReqOpt[0].OptionStr = (UINT8*)"tsize"; + OptBuf[0] = '0'; + OptBuf[1] = 0; + ReqOpt[0].ValueStr = OptBuf; + + Status = Mtftp4->GetInfo ( + Mtftp4, + NULL, + (UINT8*)FilePath, + NULL, + 1, + ReqOpt, + &PktLen, + &Packet + ); + + if (EFI_ERROR (Status)) { + goto Error; + } + + Status = Mtftp4->ParseOptions ( + Mtftp4, + PktLen, + Packet, + (UINT32 *) &OptCnt, + &TableOfOptions + ); + if (EFI_ERROR (Status)) { + goto Error; + } + + Option = TableOfOptions; + while (OptCnt != 0) { + if (AsciiStrnCmp ((CHAR8 *)Option->OptionStr, "tsize", 5) == 0) { + *FileSize = AsciiStrDecimalToUintn ((CHAR8 *)Option->ValueStr); + break; + } + OptCnt--; + Option++; + } + FreePool (TableOfOptions); + + if (OptCnt == 0) { + Status = EFI_UNSUPPORTED; + } + +Error : + + return Status; +} + +/** + Worker function that download the data of a file from a TFTP server given + the path of the file and its size. + + @param[in] Mtftp4 MTFTP4 protocol interface + @param[in] FilePath Path of the file, Unicode encoded + @param[in] AsciiFilePath Path of the file, ASCII encoded + @param[in] FileSize Size of the file in number of bytes + @param[in] BlockSize Value of the TFTP blksize option + @param[in] WindowSize Value of the TFTP window size option + + @retval EFI_SUCCESS The file was downloaded. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval Others The downloading of the file from the server failed + (see EFI_MTFTP4_PROTOCOL.ReadFile() status codes). + +**/ +STATIC +EFI_STATUS +DownloadFile ( + IN EFI_MTFTP4_PROTOCOL *Mtftp4, + IN CONST CHAR16 *FilePath, + IN CONST CHAR8 *AsciiFilePath, + IN UINTN FileSize, + IN UINT16 BlockSize, + IN UINT16 WindowSize + ) +{ + EFI_STATUS Status; + DOWNLOAD_CONTEXT *TftpContext; + EFI_MTFTP4_TOKEN Mtftp4Token; + UINT8 BlksizeBuf[10]; + UINT8 WindowsizeBuf[10]; + + ZeroMem (&Mtftp4Token, sizeof (EFI_MTFTP4_TOKEN)); + + TftpContext = AllocatePool (sizeof (DOWNLOAD_CONTEXT)); + if (TftpContext == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + TftpContext->FileSize = FileSize; + TftpContext->DownloadedNbOfBytes = 0; + TftpContext->LastReportedNbOfBytes = 0; + + Mtftp4Token.Filename = (UINT8*)AsciiFilePath; + Mtftp4Token.CheckPacket = CheckPacket; + Mtftp4Token.Context = (VOID*)TftpContext; + Mtftp4Token.OptionCount = 0; + Mtftp4Token.OptionList = AllocatePool (sizeof (EFI_MTFTP4_OPTION) * 2); + if (Mtftp4Token.OptionList == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + if (BlockSize != MTFTP_DEFAULT_BLKSIZE) { + Mtftp4Token.OptionList[Mtftp4Token.OptionCount].OptionStr = (UINT8 *) "blksize"; + AsciiSPrint ((CHAR8 *) BlksizeBuf, sizeof (BlksizeBuf), "%d", BlockSize); + Mtftp4Token.OptionList[Mtftp4Token.OptionCount].ValueStr = BlksizeBuf; + Mtftp4Token.OptionCount ++; + } + + if (WindowSize != MTFTP_DEFAULT_WINDOWSIZE) { + Mtftp4Token.OptionList[Mtftp4Token.OptionCount].OptionStr = (UINT8 *) "windowsize"; + AsciiSPrint ((CHAR8 *) WindowsizeBuf, sizeof (WindowsizeBuf), "%d", WindowSize); + Mtftp4Token.OptionList[Mtftp4Token.OptionCount].ValueStr = WindowsizeBuf; + Mtftp4Token.OptionCount ++; + } + + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_TFTP_DOWNLOADING), + mTftpHiiHandle, FilePath + ); + + // + // OPEN FILE + // + if (!EFI_ERROR (ShellFileExists (mLocalFilePath))) { + ShellDeleteFileByName (mLocalFilePath); + } + + Status = ShellOpenFileByName ( + mLocalFilePath, + &mFileHandle, + EFI_FILE_MODE_CREATE | + EFI_FILE_MODE_WRITE | + EFI_FILE_MODE_READ, + 0 + ); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), + mTftpHiiHandle, L"tftp", mLocalFilePath + ); + goto Error; + } + + Status = Mtftp4->ReadFile (Mtftp4, &Mtftp4Token); + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_GEN_CRLF), + mTftpHiiHandle + ); + + // + // CLOSE FILE + // + ShellCloseFile (&mFileHandle); + +Error : + if (TftpContext != NULL) { + FreePool (TftpContext); + } + + if (Mtftp4Token.OptionList != NULL) { + FreePool (Mtftp4Token.OptionList); + } + + return Status; +} + +/** + Update the progress of a file download + This procedure is called each time a new TFTP packet is received. + + @param[in] This MTFTP4 protocol interface + @param[in] Token Parameters for the download of the file + @param[in] PacketLen Length of the packet + @param[in] Packet Address of the packet + + @retval EFI_SUCCESS All packets are accepted. + +**/ +STATIC +EFI_STATUS +EFIAPI +CheckPacket ( + IN EFI_MTFTP4_PROTOCOL *This, + IN EFI_MTFTP4_TOKEN *Token, + IN UINT16 PacketLen, + IN EFI_MTFTP4_PACKET *Packet + ) +{ + DOWNLOAD_CONTEXT *Context; + CHAR16 Progress[TFTP_PROGRESS_MESSAGE_SIZE]; + UINTN NbOfKb; + UINTN Index; + UINTN LastStep; + UINTN Step; + UINTN DownloadLen; + EFI_STATUS Status; + + if ((NTOHS (Packet->OpCode)) != EFI_MTFTP4_OPCODE_DATA) { + return EFI_SUCCESS; + } + + Context = (DOWNLOAD_CONTEXT*)Token->Context; + + // + // The data in the packet are prepended with two UINT16 : + // . OpCode = EFI_MTFTP4_OPCODE_DATA + // . Block = the number of this block of data + // + DownloadLen = (UINTN)PacketLen - sizeof (Packet->OpCode) - sizeof (Packet->Data.Block); + + ShellSetFilePosition(mFileHandle, Context->DownloadedNbOfBytes); + Status = ShellWriteFile (mFileHandle, &DownloadLen, Packet->Data.Data); + if (EFI_ERROR (Status)) { + if (Context->DownloadedNbOfBytes > 0) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_GEN_CRLF), + mTftpHiiHandle + ); + } + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_WRITE), + mTftpHiiHandle, mLocalFilePath, Status + ); + return Status; + } + + if (Context->DownloadedNbOfBytes == 0) { + ShellPrintEx (-1, -1, L"%s 0 Kb", mTftpProgressFrame); + } + + Context->DownloadedNbOfBytes += DownloadLen; + NbOfKb = Context->DownloadedNbOfBytes / 1024; + + Progress[0] = L'\0'; + LastStep = (Context->LastReportedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize; + Step = (Context->DownloadedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize; + + if (Step <= LastStep) { + return EFI_SUCCESS; + } + + ShellPrintEx (-1, -1, L"%s", mTftpProgressDelete); + + Status = StrCpyS (Progress, TFTP_PROGRESS_MESSAGE_SIZE, mTftpProgressFrame); + if (EFI_ERROR(Status)) { + return Status; + } + for (Index = 1; Index < Step; Index++) { + Progress[Index] = L'='; + } + Progress[Step] = L'>'; + + UnicodeSPrint ( + Progress + (sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 1, + sizeof (Progress) - sizeof (mTftpProgressFrame), + L" %7d Kb", + NbOfKb + ); + Context->LastReportedNbOfBytes = Context->DownloadedNbOfBytes; + + ShellPrintEx (-1, -1, L"%s", Progress); + + return EFI_SUCCESS; +} + +/** + Retrieve HII package list from ImageHandle and publish to HII database. + + @param ImageHandle The image handle of the process. + + @return HII handle. +**/ +EFI_HII_HANDLE +InitializeHiiPackage ( + EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + EFI_HII_PACKAGE_LIST_HEADER *PackageList; + EFI_HII_HANDLE HiiHandle; + + // + // Retrieve HII package list from ImageHandle + // + Status = gBS->OpenProtocol ( + ImageHandle, + &gEfiHiiPackageListProtocolGuid, + (VOID **)&PackageList, + ImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return NULL; + } + + // + // Publish HII package list to HII Database. + // + Status = gHiiDatabase->NewPackageList ( + gHiiDatabase, + PackageList, + NULL, + &HiiHandle + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return NULL; + } + return HiiHandle; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.h new file mode 100644 index 00000000..e4c90fa8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.h @@ -0,0 +1,69 @@ +/** @file + Header file for 'tftp' command functions. + + Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.
+ Copyright (c) 2015, ARM Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _TFTP_H_ +#define _TFTP_H_ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern EFI_HII_HANDLE mTftpHiiHandle; + +typedef struct { + UINTN FileSize; + UINTN DownloadedNbOfBytes; + UINTN LastReportedNbOfBytes; +} DOWNLOAD_CONTEXT; + +/** + Function for 'tftp' command. + + @param[in] ImageHandle The image handle. + @param[in] SystemTable The system table. + + @retval SHELL_SUCCESS Command completed successfully. + @retval SHELL_INVALID_PARAMETER Command usage error. + @retval SHELL_ABORTED The user aborts the operation. + @retval value Unknown error. +**/ +SHELL_STATUS +RunTftp ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Retrieve HII package list from ImageHandle and publish to HII database. + + @param ImageHandle The image handle of the process. + + @return HII handle. +**/ +EFI_HII_HANDLE +InitializeHiiPackage ( + EFI_HANDLE ImageHandle + ); +#endif // _TFTP_H_ diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.uni b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.uni new file mode 100644 index 00000000..ebac9c6c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.uni @@ -0,0 +1,94 @@ +// /** +// +// (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
+// Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// Module Name: +// +// Tftp.uni +// +// Abstract: +// +// String definitions for UEFI Shell TFTP command +// +// +// **/ + +/=# + +#langdef en-US "english" + +#string STR_GEN_TOO_MANY #language en-US "%H%s%N: Too many arguments\r\n" +#string STR_GEN_TOO_FEW #language en-US "%H%s%N: Too few arguments\r\n" +#string STR_GEN_PARAM_INV #language en-US "%H%s%N: Invalid argument - '%H%s%N'\r\n" +#string STR_GEN_PROBLEM #language en-US "%H%s%N: Unknown flag - '%H%s%N'\r\n" +#string STR_GEN_FILE_OPEN_FAIL #language en-US "%H%s%N: Cannot open file - '%H%s%N'\r\n" +#string STR_GEN_CRLF #language en-US "\r\n" + +#string STR_TFTP_ERR_NO_NIC #language en-US "No network interface card found.\r\n" +#string STR_TFTP_ERR_NIC_NAME #language en-US "Failed to get the name of the network interface card number %d - %r\r\n" +#string STR_TFTP_ERR_OPEN_PROTOCOL #language en-US "Unable to open MTFTP4 protocol on '%H%s%N' - %r\r\n" +#string STR_TFTP_ERR_CONFIGURE #language en-US "Unable to configure MTFTP4 protocol on '%H%s%N' - %r\r\n" +#string STR_TFTP_ERR_FILE_SIZE #language en-US "Unable to get the size of the file '%H%s%N' on '%H%s%N' - %r\r\n" +#string STR_TFTP_ERR_DOWNLOAD #language en-US "Unable to download the file '%H%s%N' on '%H%s%N' - %r\r\n" +#string STR_TFTP_ERR_WRITE #language en-US "Unable to write into file '%H%s%N' - %r\r\n" +#string STR_TFTP_ERR_NIC_NOT_FOUND #language en-US "Network Interface Card '%H%s%N' not found.\r\n" +#string STR_TFTP_DOWNLOADING #language en-US "Downloading the file '%H%s%N'\r\n" +#string STR_TFTP_STRING #language en-US "%s" + +#string STR_GET_HELP_TFTP #language en-US "" +".TH tftp 0 "Download a file from TFTP server."\r\n" +".SH NAME\r\n" +"Download a file from TFTP server.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"TFTP [-i interface] [-l ] [-r ] [-c ] [-t ]\r\n" +" [-s ] [-w ] host remotefilepath [localfilepath]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -i interface - Specifies an adapter name, i.e., eth0.\r\n" +" -l port - Specifies the local port number. Default value is 0\r\n" +" and the port number is automatically assigned.\r\n" +" -r port - Specifies the remote port number. Default value is 69.\r\n" +" -c - The number of times to transmit request packets and\r\n" +" wait for a response. The default value is 6. Set to zero\r\n" +" also means to use the default value.\r\n" +" -t - The number of seconds to wait for a response after\r\n" +" sending a request packet. Default value is 4s.\r\n" +" -s - Specifies the TFTP blksize option as defined in RFC 2348.\r\n" +" Valid range is between 8 and 65464, default value is 512.\r\n" +" -w - Specifies the TFTP windowsize option as defined in RFC 7440.\r\n" +" Valid range is between 1 and 64, default value is 1.\r\n" +" host - Specify TFTP Server IPv4 address.\r\n" +" remotefilepath - TFTP server file path to download the file.\r\n" +" localfilepath - Local destination file path.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. The TFTP command allows to get the file specified by its 'remotefilepath'\r\n" +" path from the TFTP server specified by its 'host' IPv4 address. If the\r\n" +" optional 'localfilepath' parameter is provided, the downloaded file is\r\n" +" stored locally using the provided file path. If the local file path is\r\n" +" not specified, the file is stored in the current directory using the file\r\n" +" server's name.\r\n" +" 2. Before using the TFTP command, the network interface intended to be\r\n" +" used to retrieve the file must be configured. This configuration may be\r\n" +" done by means of the 'ifconfig' command.\r\n" +" 3. If a network interface is defined with the '-i' option then only this\r\n" +" interface will be used to retrieve the remote file. Otherwise, all network\r\n" +" interfaces are tried in the order they have been discovered during the\r\n" +" DXE phase.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To get the file "dir1/file1.dat" from the TFTP server 192.168.1.1 and\r\n" +" store it as file2.dat in the current directory :\r\n" +" fs0:\> tftp 192.168.1.1 dir1/file1.dat file2.dat\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_INVALID_PARAMETER One of the passed-in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpApp.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpApp.c new file mode 100644 index 00000000..c43755bf --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpApp.c @@ -0,0 +1,48 @@ +/** @file + Entrypoint of "tftp" shell standalone application. + + Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.
+ Copyright (c) 2015, ARM Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "Tftp.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_GET_HELP_TFTP); + +/** + Entry point of Tftp standalone application. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. + + @retval EFI_SUCCESS Tftp command is executed successfully. + @retval EFI_ABORTED HII package was failed to initialize. + @retval others Other errors when executing tftp command. +**/ +EFI_STATUS +EFIAPI +TftpAppInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + mTftpHiiHandle = InitializeHiiPackage (ImageHandle); + if (mTftpHiiHandle == NULL) { + return EFI_ABORTED; + } + + Status = (EFI_STATUS)RunTftp (ImageHandle, SystemTable); + HiiRemovePackages (mTftpHiiHandle); + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpApp.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpApp.inf new file mode 100644 index 00000000..4eb02f86 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpApp.inf @@ -0,0 +1,55 @@ +## @file +# Provides Shell 'tftp' standalone application. +# +# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.
+# Copyright (c) 2015, ARM Ltd. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = tftp + FILE_GUID = 8DC58D0D-67F5-4B97-9DFC-E442BB9A5648 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = TftpAppInitialize +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +[Sources.common] + Tftp.uni + Tftp.h + Tftp.c + TftpApp.c + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + NetworkPkg/NetworkPkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + ShellLib + UefiLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + UefiApplicationEntryPoint + UefiHiiServicesLib + HiiLib + FileHandleLib + NetLib + +[Protocols] + gEfiManagedNetworkServiceBindingProtocolGuid ## CONSUMES + gEfiMtftp4ServiceBindingProtocolGuid ## CONSUMES + gEfiMtftp4ProtocolGuid ## CONSUMES + gEfiHiiPackageListProtocolGuid ## CONSUMES diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpDynamicCommand.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpDynamicCommand.c new file mode 100644 index 00000000..a657fc2c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpDynamicCommand.c @@ -0,0 +1,126 @@ +/** @file + Produce "tftp" shell dynamic command. + + Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.
+ Copyright (c) 2015, ARM Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "Tftp.h" +#include + +/** + This is the shell command handler function pointer callback type. This + function handles the command when it is invoked in the shell. + + @param[in] This The instance of the EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL. + @param[in] SystemTable The pointer to the system table. + @param[in] ShellParameters The parameters associated with the command. + @param[in] Shell The instance of the shell protocol used in the context + of processing this command. + + @return EFI_SUCCESS the operation was successful + @return other the operation failed. +**/ +SHELL_STATUS +EFIAPI +TftpCommandHandler ( + IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This, + IN EFI_SYSTEM_TABLE *SystemTable, + IN EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters, + IN EFI_SHELL_PROTOCOL *Shell + ) +{ + gEfiShellParametersProtocol = ShellParameters; + gEfiShellProtocol = Shell; + return RunTftp (gImageHandle, SystemTable); +} + +/** + This is the command help handler function pointer callback type. This + function is responsible for displaying help information for the associated + command. + + @param[in] This The instance of the EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL. + @param[in] Language The pointer to the language string to use. + + @return string Pool allocated help string, must be freed by caller +**/ +CHAR16 * +EFIAPI +TftpCommandGetHelp ( + IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This, + IN CONST CHAR8 *Language + ) +{ + return HiiGetString (mTftpHiiHandle, STRING_TOKEN (STR_GET_HELP_TFTP), Language); +} + +EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL mTftpDynamicCommand = { + L"tftp", + TftpCommandHandler, + TftpCommandGetHelp +}; + +/** + Entry point of Tftp Dynamic Command. + + Produce the DynamicCommand protocol to handle "tftp" command. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. + + @retval EFI_SUCCESS Tftp command is executed successfully. + @retval EFI_ABORTED HII package was failed to initialize. + @retval others Other errors when executing tftp command. +**/ +EFI_STATUS +EFIAPI +TftpCommandInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + mTftpHiiHandle = InitializeHiiPackage (ImageHandle); + if (mTftpHiiHandle == NULL) { + return EFI_ABORTED; + } + + Status = gBS->InstallProtocolInterface ( + &ImageHandle, + &gEfiShellDynamicCommandProtocolGuid, + EFI_NATIVE_INTERFACE, + &mTftpDynamicCommand + ); + ASSERT_EFI_ERROR (Status); + return Status; +} + +/** + Tftp driver unload handler. + + @param ImageHandle The image handle of the process. + + @retval EFI_SUCCESS The image is unloaded. + @retval Others Failed to unload the image. +**/ +EFI_STATUS +EFIAPI +TftpUnload ( + IN EFI_HANDLE ImageHandle +) +{ + EFI_STATUS Status; + Status = gBS->UninstallProtocolInterface ( + ImageHandle, + &gEfiShellDynamicCommandProtocolGuid, + &mTftpDynamicCommand + ); + if (EFI_ERROR (Status)) { + return Status; + } + HiiRemovePackages (mTftpHiiHandle); + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpDynamicCommand.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpDynamicCommand.inf new file mode 100644 index 00000000..695af555 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpDynamicCommand.inf @@ -0,0 +1,60 @@ +## @file +# Provides Shell 'tftp' dynamic command. +# +# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.
+# Copyright (c) 2015, ARM Ltd. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = tftpDynamicCommand + FILE_GUID = A487A478-51EF-48AA-8794-7BEE2A0562F1 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = TftpCommandInitialize + UNLOAD_IMAGE = TftpUnload +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +[Sources.common] + Tftp.uni + Tftp.h + Tftp.c + TftpDynamicCommand.c + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + NetworkPkg/NetworkPkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + ShellLib + UefiLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiHiiServicesLib + HiiLib + FileHandleLib + NetLib + +[Protocols] + gEfiManagedNetworkServiceBindingProtocolGuid ## CONSUMES + gEfiMtftp4ServiceBindingProtocolGuid ## CONSUMES + gEfiMtftp4ProtocolGuid ## CONSUMES + gEfiHiiPackageListProtocolGuid ## CONSUMES + gEfiShellDynamicCommandProtocolGuid ## PRODUCES + +[DEPEX] + TRUE diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Guid/ShellAliasGuid.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Guid/ShellAliasGuid.h new file mode 100644 index 00000000..82887479 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Guid/ShellAliasGuid.h @@ -0,0 +1,19 @@ +/** @file + GUID for Shell Variable for Get/Set via runtime services. + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SHELL_ALIAS_VARIABLE_GUID_H_ +#define _SHELL_ALIAS_VARIABLE_GUID_H_ + +#define SHELL_ALIAS_VARIABLE_GUID \ +{ \ + 0x0053d9d6, 0x2659, 0x4599, { 0xa2, 0x6b, 0xef, 0x45, 0x36, 0xe6, 0x31, 0xa9 } \ +} + +extern EFI_GUID gShellAliasGuid; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Guid/ShellEnvironment2Ext.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Guid/ShellEnvironment2Ext.h new file mode 100644 index 00000000..7c2829e5 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Guid/ShellEnvironment2Ext.h @@ -0,0 +1,19 @@ +/** @file + GUID for EFI shell Environment2 Extension. + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SHELLPKG_SHELL_ENV2_EXT_GUID_H_ +#define _SHELLPKG_SHELL_ENV2_EXT_GUID_H_ + +#define SHELLPKG_SHELL_ENV2_EXT_GUID \ +{ \ + 0xd2c18636, 0x40e5, 0x4eb5, {0xa3, 0x1b, 0x36, 0x69, 0x5f, 0xd4, 0x2c, 0x87} \ +} + +extern EFI_GUID gEfiShellEnvironment2ExtGuid; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Guid/ShellLibHiiGuid.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Guid/ShellLibHiiGuid.h new file mode 100644 index 00000000..eacd614d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Guid/ShellLibHiiGuid.h @@ -0,0 +1,85 @@ +/** @file + GUIDs for HII package list installed by Shell libraries. + + Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SHELLLIB_HII_GUID_H_ +#define _SHELLLIB_HII_GUID_H_ + +#define HANDLE_PARSING_HII_GUID \ + { \ + 0xb8969637, 0x81de, 0x43af, { 0xbc, 0x9a, 0x24, 0xd9, 0x89, 0x13, 0xf2, 0xf6 } \ + } + +#define SHELL_DEBUG1_HII_GUID \ + { \ + 0x25f200aa, 0xd3cb, 0x470a, { 0xbf, 0x51, 0xe7, 0xd1, 0x62, 0xd2, 0x2e, 0x6f } \ + } + +#define SHELL_DRIVER1_HII_GUID \ + { \ + 0xaf0b742, 0x63ec, 0x45bd, {0x8d, 0xb6, 0x71, 0xad, 0x7f, 0x2f, 0xe8, 0xe8} \ + } + +#define SHELL_INSTALL1_HII_GUID \ + { \ + 0x7d574d54, 0xd364, 0x4d4a, { 0x95, 0xe3, 0x49, 0x45, 0xdb, 0x7a, 0xd3, 0xee } \ + } + +#define SHELL_LEVEL1_HII_GUID \ + { \ + 0xdec5daa4, 0x6781, 0x4820, { 0x9c, 0x63, 0xa7, 0xb0, 0xe4, 0xf1, 0xdb, 0x31 } \ + } + +#define SHELL_LEVEL2_HII_GUID \ + { \ + 0xf95a7ccc, 0x4c55, 0x4426, { 0xa7, 0xb4, 0xdc, 0x89, 0x61, 0x95, 0xb, 0xae } \ + } + +#define SHELL_LEVEL3_HII_GUID \ + { \ + 0x4344558d, 0x4ef9, 0x4725, { 0xb1, 0xe4, 0x33, 0x76, 0xe8, 0xd6, 0x97, 0x4f } \ + } + +#define SHELL_NETWORK1_HII_GUID \ + { \ + 0xf3d301bb, 0xf4a5, 0x45a8, { 0xb0, 0xb7, 0xfa, 0x99, 0x9c, 0x62, 0x37, 0xae } \ + } + +#define SHELL_NETWORK2_HII_GUID \ + { \ + 0x174b2b5, 0xf505, 0x4b12, { 0xaa, 0x60, 0x59, 0xdf, 0xf8, 0xd6, 0xea, 0x37 } \ + } + +#define SHELL_TFTP_HII_GUID \ + { \ + 0x738a9314, 0x82c1, 0x4592, { 0x8f, 0xf7, 0xc1, 0xbd, 0xf1, 0xb2, 0x0e, 0xd4 } \ + } + +#define SHELL_HTTP_HII_GUID \ + { \ + 0x390f84b3, 0x221c, 0x4d9e, { 0xb5, 0x06, 0x6d, 0xb9, 0x42, 0x3e, 0x0a, 0x7e } \ + } + +#define SHELL_BCFG_HII_GUID \ + { \ + 0x5f5f605d, 0x1583, 0x4a2d, {0xa6, 0xb2, 0xeb, 0x12, 0xda, 0xb4, 0xa2, 0xb6 } \ + } + +extern EFI_GUID gHandleParsingHiiGuid; +extern EFI_GUID gShellDebug1HiiGuid; +extern EFI_GUID gShellDriver1HiiGuid; +extern EFI_GUID gShellInstall1HiiGuid; +extern EFI_GUID gShellLevel1HiiGuid; +extern EFI_GUID gShellLevel2HiiGuid; +extern EFI_GUID gShellLevel3HiiGuid; +extern EFI_GUID gShellNetwork1HiiGuid; +extern EFI_GUID gShellNetwork2HiiGuid; +extern EFI_GUID gShellTftpHiiGuid; +extern EFI_GUID gShellHttpHiiGuid; +extern EFI_GUID gShellBcfgHiiGuid; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Guid/ShellMapGuid.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Guid/ShellMapGuid.h new file mode 100644 index 00000000..9af44aa3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Guid/ShellMapGuid.h @@ -0,0 +1,19 @@ +/** @file + GUID for Shell Map for Get/Set via runtime services. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SHELL_MAP_GUID_H_ +#define _SHELL_MAP_GUID_H_ + +#define SHELL_MAP_GUID \ +{ \ + 0x51271e13, 0x7de3, 0x43af, { 0x8b, 0xc2, 0x71, 0xad, 0x3b, 0x82, 0x43, 0x25 } \ +} + +extern EFI_GUID gShellMapGuid; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Guid/ShellPkgTokenSpace.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Guid/ShellPkgTokenSpace.h new file mode 100644 index 00000000..4ffa1b78 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Guid/ShellPkgTokenSpace.h @@ -0,0 +1,19 @@ +/** @file + GUID for ShellPkg PCD Token Space. + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SHELLPKG_TOKEN_SPACE_GUID_H_ +#define _SHELLPKG_TOKEN_SPACE_GUID_H_ + +#define EFI_SHELLPKG_TOKEN_SPACE_GUID \ +{ \ + 0x171e9188, 0x31d3, 0x40f5, { 0xb1, 0xc, 0x53, 0x9b, 0x2d, 0xb9, 0x40, 0xcd } \ +} + +extern EFI_GUID gEfiShellPkgTokenSpaceGuid; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Guid/ShellVariableGuid.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Guid/ShellVariableGuid.h new file mode 100644 index 00000000..8142922c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Guid/ShellVariableGuid.h @@ -0,0 +1,19 @@ +/** @file + GUID for Shell Variable for Get/Set via runtime services. + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SHELL_VARIABLE_GUID_H_ +#define _SHELL_VARIABLE_GUID_H_ + +#define SHELL_VARIABLE_GUID \ +{ \ + 0x158def5a, 0xf656, 0x419c, { 0xb0, 0x27, 0x7a, 0x31, 0x92, 0xc0, 0x79, 0xd2 } \ +} + +extern EFI_GUID gShellVariableGuid; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Library/AcpiViewCommandLib.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Library/AcpiViewCommandLib.h new file mode 100644 index 00000000..0d2468e9 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Library/AcpiViewCommandLib.h @@ -0,0 +1,46 @@ +/** @file + Library providing 'acpiview' functionality to display and + validate installed ACPI tables. + + Copyright (c) 2016 - 2020, ARM Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef ACPI_VIEW_COMMAND_LIB_H_ +#define ACPI_VIEW_COMMAND_LIB_H_ + +/** + Dump a buffer to a file. Print error message if a file cannot be created. + + @param[in] FileName The filename that shall be created to contain the buffer. + @param[in] Buffer Pointer to buffer that shall be dumped. + @param[in] BufferSize The size of buffer to be dumped in bytes. + + @return The number of bytes that were written +**/ +UINTN +EFIAPI +ShellDumpBufferToFile ( + IN CONST CHAR16* FileNameBuffer, + IN CONST VOID* Buffer, + IN CONST UINTN BufferSize + ); + +/** + Display and validate ACPI tables. + + @param[in] ImageHandle Handle to the Image (NULL if internal). + @param[in] SystemTable Pointer to the System Table (NULL if internal). + + @retval SHELL_INVALID_PARAMETER The command line invocation could not be parsed. + @retval SHELL_NOT_FOUND The command failed. + @retval SHELL_SUCCESS The command was successful. +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunAcpiView ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +#endif // UEFI_SHELL_ACPIVIEW_COMMAND_LIB_H_ diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Library/BcfgCommandLib.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Library/BcfgCommandLib.h new file mode 100644 index 00000000..77eb723f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Library/BcfgCommandLib.h @@ -0,0 +1,46 @@ +/** @file + Header file for BCFG command library. + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _BCFG_COMMAND_LIB_H_ +#define _BCFG_COMMAND_LIB_H_ + +/** + "Constructor" for the library. + + This will register the handler for the bcfg command. + + @param[in] ImageHandle the image handle of the process + @param[in] SystemTable the EFI System Table pointer + @param[in] Name the profile name to use + + @retval EFI_SUCCESS the shell command handlers were installed sucessfully + @retval EFI_UNSUPPORTED the shell level required was not found. +**/ +EFI_STATUS +EFIAPI +BcfgLibraryRegisterBcfgCommand ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable, + IN CONST CHAR16 *Name + ); + +/** + "Destructor" for the library. free any resources. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. +**/ +EFI_STATUS +EFIAPI +BcfgLibraryUnregisterBcfgCommand ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +#endif + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Library/HandleParsingLib.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Library/HandleParsingLib.h new file mode 100644 index 00000000..7d488aec --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Library/HandleParsingLib.h @@ -0,0 +1,404 @@ +/** @file + Provides interface to advanced shell functionality for parsing both handle and protocol database. + + Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __HANDLE_PARSING_LIB__ +#define __HANDLE_PARSING_LIB__ + +#include + +/** + Function to add a new GUID/Name mapping. + + This cannot overwrite an existing mapping. + + @param[in] Guid The Guid + @param[in] TheName The Guid's name + @param[in] Lang RFC4646 language code list or NULL + + @retval EFI_SUCCESS The operation was sucessful + @retval EFI_ACCESS_DENIED There was a duplicate + @retval EFI_OUT_OF_RESOURCES A memory allocation failed +**/ +EFI_STATUS +EFIAPI +AddNewGuidNameMapping( + IN CONST EFI_GUID *Guid, + IN CONST CHAR16 *TheName, + IN CONST CHAR8 *Lang OPTIONAL + ); + +/** + Function to get the name of a protocol or struct from it's GUID. + + If Guid is NULL, then ASSERT. + + @param[in] Guid The GUID to look for the name of. + @param[in] Lang The language to use. + + @return The pointer to a string of the name. The caller + is responsible to free this memory. +**/ +CHAR16* +EFIAPI +GetStringNameFromGuid( + IN CONST EFI_GUID *Guid, + IN CONST CHAR8 *Lang OPTIONAL + ); + +/** + Function to get the Guid for a protocol or struct based on it's string name. + + Do not free or modify the returned GUID. + + @param[in] Name The pointer to the string name. + @param[in] Lang The pointer to the language code (string). + @param[out] Guid The pointer to the pointer to the Guid. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +GetGuidFromStringName( + IN CONST CHAR16 *Name, + IN CONST CHAR8 *Lang OPTIONAL, + OUT EFI_GUID **Guid + ); + +/** + Function to dump protocol information from a handle. + + This function will return a allocated string buffer containing the + information. The caller is responsible for freeing the memory. + + If Guid is NULL, ASSERT(). + If TheHandle is NULL, ASSERT(). + + @param[in] TheHandle The handle to dump information from. + @param[in] Guid The GUID of the protocol to dump. + @param[in] Verbose TRUE for extra info. FALSE otherwise. + + @return The pointer to string. + @retval NULL An error was encountered. +**/ +CHAR16* +EFIAPI +GetProtocolInformationDump( + IN CONST EFI_HANDLE TheHandle, + IN CONST EFI_GUID *Guid, + IN CONST BOOLEAN Verbose + ); + +/** + Function to retrieve the driver name (if possible) from the ComponentName or + ComponentName2 protocol. + + The string returned must be callee freed. + + @param[in] TheHandle The driver handle to get the name of. + @param[in] Language The language to use. + + @retval NULL The name could not be found. + @return A pointer to the string name. Do not de-allocate the memory. +**/ +CONST CHAR16* +EFIAPI +GetStringNameFromHandle( + IN CONST EFI_HANDLE TheHandle, + IN CONST CHAR8 *Language + ); + +/** + Get best support language for this driver. + + First base on the user input language to search, second base on the current + platform used language to search, third get the first language from the + support language list. The caller need to free the buffer of the best language. + + @param[in] SupportedLanguages The support languages for this driver. + @param[in] InputLanguage The user input language. + @param[in] Iso639Language Whether get language for ISO639. + + @return The best support language for this driver. +**/ +CHAR8 * +EFIAPI +GetBestLanguageForDriver ( + IN CONST CHAR8 *SupportedLanguages, + IN CONST CHAR8 *InputLanguage, + IN BOOLEAN Iso639Language + ); + +#define HR_UNKNOWN 0 +#define HR_IMAGE_HANDLE BIT1 +#define HR_DRIVER_BINDING_HANDLE BIT2 // has driver binding +#define HR_DEVICE_DRIVER BIT3 // device driver (hybrid?) +#define HR_BUS_DRIVER BIT4 // a bus driver (hybrid?) +#define HR_DRIVER_CONFIGURATION_HANDLE BIT5 +#define HR_DRIVER_DIAGNOSTICS_HANDLE BIT6 +#define HR_COMPONENT_NAME_HANDLE BIT7 +#define HR_DEVICE_HANDLE BIT8 +#define HR_PARENT_HANDLE BIT9 +#define HR_CONTROLLER_HANDLE BIT10 +#define HR_CHILD_HANDLE BIT11 +#define HR_VALID_MASK (BIT1|BIT2|BIT3|BIT4|BIT5|BIT6|BIT7|BIT8|BIT9|BIT10|BIT11) + +/** + Gets all the related EFI_HANDLEs based on the mask supplied. + + This function will scan all EFI_HANDLES in the UEFI environment's handle database + and return all the ones with the specified relationship (Mask) to the specified + controller handle. + + If both DriverBindingHandle and ControllerHandle are NULL, then ASSERT. + If MatchingHandleCount is NULL, then ASSERT. + + If MatchingHandleBuffer is not NULL upon a successful return, the memory must be + caller freed. + + @param[in] DriverBindingHandle The handle with Driver Binding protocol on it. + @param[in] ControllerHandle The handle with Device Path protocol on it. + @param[in] Mask The mask of what relationship(s) is desired. + @param[in] MatchingHandleCount The pointer to UINTN specifying number of HANDLES in + MatchingHandleBuffer. + @param[out] MatchingHandleBuffer On a successful return, a buffer of MatchingHandleCount + EFI_HANDLEs with a terminating NULL EFI_HANDLE. + + @retval EFI_SUCCESS The operation was successful, and any related handles + are in MatchingHandleBuffer. + @retval EFI_NOT_FOUND No matching handles were found. + @retval EFI_INVALID_PARAMETER A parameter was invalid or out of range. + @sa ParseHandleDatabaseByRelationshipWithType +**/ +EFI_STATUS +EFIAPI +ParseHandleDatabaseByRelationship ( + IN CONST EFI_HANDLE DriverBindingHandle OPTIONAL, + IN CONST EFI_HANDLE ControllerHandle OPTIONAL, + IN CONST UINTN Mask, + IN UINTN *MatchingHandleCount, + OUT EFI_HANDLE **MatchingHandleBuffer OPTIONAL + ); + +/** + Gets all the related EFI_HANDLEs based on the mask supplied. + + This function scans all EFI_HANDLES in the UEFI environment's handle database + and returns the ones with the specified relationship (Mask) to the specified + controller handle. + + If both DriverBindingHandle and ControllerHandle are NULL, then ASSERT. + If MatchingHandleCount is NULL, then ASSERT. + + If MatchingHandleBuffer is not NULL upon a successful return the memory must be + caller freed. + + @param[in] DriverBindingHandle The handle with Driver Binding protocol on it. + @param[in] ControllerHandle The handle with Device Path protocol on it. + @param[in] MatchingHandleCount The pointer to UINTN that specifies the number of HANDLES in + MatchingHandleBuffer. + @param[out] MatchingHandleBuffer On a successful return, a buffer of MatchingHandleCount + EFI_HANDLEs with a terminating NULL EFI_HANDLE. + @param[out] HandleType An array of type information. + + @retval EFI_SUCCESS The operation was successful, and any related handles + are in MatchingHandleBuffer. + @retval EFI_NOT_FOUND No matching handles were found. + @retval EFI_INVALID_PARAMETER A parameter was invalid or out of range. +**/ +EFI_STATUS +EFIAPI +ParseHandleDatabaseByRelationshipWithType ( + IN CONST EFI_HANDLE DriverBindingHandle OPTIONAL, + IN CONST EFI_HANDLE ControllerHandle OPTIONAL, + IN UINTN *HandleCount, + OUT EFI_HANDLE **HandleBuffer, + OUT UINTN **HandleType + ); + +/** + Gets handles for any parents of the passed in controller. + + @param[in] ControllerHandle The handle of the controller. + @param[in] Count The pointer to the number of handles in + MatchingHandleBuffer on return. + @param[out] Buffer The buffer containing handles on a successful + return. + @retval EFI_SUCCESS The operation was successful. + @sa ParseHandleDatabaseByRelationship +**/ +#define PARSE_HANDLE_DATABASE_PARENTS(ControllerHandle, Count, Buffer) \ + ParseHandleDatabaseByRelationship(NULL, ControllerHandle, HR_PARENT_HANDLE, Count, Buffer) + +/** + Gets handles for any UEFI drivers of the passed in controller. + + @param[in] ControllerHandle The handle of the controller. + @param[in] Count The pointer to the number of handles in + MatchingHandleBuffer on return. + @param[out] Buffer The buffer containing handles on a successful + return. + @retval EFI_SUCCESS The operation was successful. + @sa ParseHandleDatabaseByRelationship +**/ +#define PARSE_HANDLE_DATABASE_UEFI_DRIVERS(ControllerHandle, Count, Buffer) \ + ParseHandleDatabaseByRelationship(NULL, ControllerHandle, HR_DRIVER_BINDING_HANDLE|HR_DEVICE_DRIVER, Count, Buffer) + +/** + Gets handles for any children of the passed in controller by the passed in driver handle. + + @param[in] DriverHandle The handle of the driver. + @param[in] ControllerHandle The handle of the controller. + @param[in] Count The pointer to the number of handles in + MatchingHandleBuffer on return. + @param[out] Buffer The buffer containing handles on a successful + return. + @retval EFI_SUCCESS The operation was successful. + @sa ParseHandleDatabaseByRelationship +**/ +#define PARSE_HANDLE_DATABASE_MANAGED_CHILDREN(DriverHandle, ControllerHandle, Count, Buffer) \ + ParseHandleDatabaseByRelationship(DriverHandle, ControllerHandle, HR_CHILD_HANDLE|HR_DEVICE_HANDLE, Count, Buffer) + +/** + Gets handles for any devices managed by the passed in driver. + + @param[in] DriverHandle The handle of the driver. + @param[in] Count The pointer to the number of handles in + MatchingHandleBuffer on return. + @param[out] Buffer The buffer containing handles on a successful + return. + @retval EFI_SUCCESS The operation was successful. + @sa ParseHandleDatabaseByRelationship +**/ +#define PARSE_HANDLE_DATABASE_DEVICES(DriverHandle, Count, Buffer) \ + ParseHandleDatabaseByRelationship(DriverHandle, NULL, HR_CONTROLLER_HANDLE|HR_DEVICE_HANDLE, Count, Buffer) + +/** + Gets handles for any child devices produced by the passed in driver. + + @param[in] DriverHandle The handle of the driver. + @param[in] MatchingHandleCount The pointer to the number of handles in + MatchingHandleBuffer on return. + @param[out] MatchingHandleBuffer The buffer containing handles on a successful + return. + @retval EFI_SUCCESS The operation was successful. + @sa ParseHandleDatabaseByRelationship +**/ +EFI_STATUS +EFIAPI +ParseHandleDatabaseForChildDevices( + IN CONST EFI_HANDLE DriverHandle, + IN UINTN *MatchingHandleCount, + OUT EFI_HANDLE **MatchingHandleBuffer OPTIONAL + ); + +/** + Gets handles for any child controllers of the passed in controller. + + @param[in] ControllerHandle The handle of the "parent controller". + @param[out] MatchingHandleCount The pointer to the number of handles in + MatchingHandleBuffer on return. + @param[out] MatchingHandleBuffer The buffer containing handles on a successful + return. + @retval EFI_SUCCESS The operation was successful. + @sa ParseHandleDatabaseByRelationship +**/ +EFI_STATUS +EFIAPI +ParseHandleDatabaseForChildControllers( + IN CONST EFI_HANDLE ControllerHandle, + OUT UINTN *MatchingHandleCount, + OUT EFI_HANDLE **MatchingHandleBuffer OPTIONAL + ); + + +/** + Function to retrieve the human-friendly index of a given handle. If the handle + does not have a index one will be automatically assigned. The index value is valid + until the termination of the shell application. + + @param[in] TheHandle The handle to retrieve an index for. + + @retval 0 A memory allocation failed. + @return The index of the handle. + +**/ +UINTN +EFIAPI +ConvertHandleToHandleIndex( + IN CONST EFI_HANDLE TheHandle + ); + +/** + Function to retrieve the EFI_HANDLE from the human-friendly index. + + @param[in] TheIndex The index to retrieve the EFI_HANDLE for. + + @retval NULL The index was invalid. + @return The EFI_HANDLE that index represents. + +**/ +EFI_HANDLE +EFIAPI +ConvertHandleIndexToHandle( + IN CONST UINTN TheIndex + ); + +/** + Function to get all handles that support a given protocol or all handles. + + The caller is responsible to free this memory. + + @param[in] ProtocolGuid The guid of the protocol to get handles for. If NULL + then the function will return all handles. + + @retval NULL A memory allocation failed. + @return A NULL terminated list of handles. +**/ +EFI_HANDLE* +EFIAPI +GetHandleListByProtocol ( + IN CONST EFI_GUID *ProtocolGuid OPTIONAL + ); + +/** + Function to get all handles that support some protocols. + + The caller is responsible to free this memory. + + @param[in] ProtocolGuids A NULL terminated list of protocol GUIDs. + + @retval NULL A memory allocation failed. + @retval NULL ProtocolGuids was NULL. + @return A NULL terminated list of EFI_HANDLEs. +**/ +EFI_HANDLE* +EFIAPI +GetHandleListByProtocolList ( + IN CONST EFI_GUID **ProtocolGuids + ); + + +/** + Return all supported GUIDs. + + @param[out] Guids The buffer to return all supported GUIDs. + @param[in, out] Count On input, the count of GUIDs the buffer can hold, + On output, the count of GUIDs to return. + + @retval EFI_INVALID_PARAMETER Count is NULL. + @retval EFI_BUFFER_TOO_SMALL Buffer is not enough to hold all GUIDs. + @retval EFI_SUCCESS GUIDs are returned successfully. +**/ +EFI_STATUS +EFIAPI +GetAllMappingGuids ( + OUT EFI_GUID *Guids, + IN OUT UINTN *Count + ); + +#endif // __HANDLE_PARSING_LIB__ diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Library/ShellCEntryLib.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Library/ShellCEntryLib.h new file mode 100644 index 00000000..5ebf986a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Library/ShellCEntryLib.h @@ -0,0 +1,34 @@ +/** @file + Provides application point extension for "C" style main function. + + Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SHELL_C_ENTRY_LIB_ +#define _SHELL_C_ENTRY_LIB_ + +/** + UEFI application entry point which has an interface similar to a + standard C main function. + + The ShellCEntryLib library instance wrappers the actual UEFI application + entry point and calls this ShellAppMain function. + + @param[in] Argc The number of parameters. + @param[in] Argv The array of pointers to parameters. + + @retval 0 The application exited normally. + @retval Other An error occurred. + +**/ +INTN +EFIAPI +ShellAppMain ( + IN UINTN Argc, + IN CHAR16 **Argv + ); + +#endif + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Library/ShellCommandLib.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Library/ShellCommandLib.h new file mode 100644 index 00000000..61f7317b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Library/ShellCommandLib.h @@ -0,0 +1,798 @@ +/** @file + Provides interface to shell internal functions for shell commands. + + This library is for use ONLY by shell commands linked into the shell application. + This library will not function if it is used for UEFI Shell 2.0 Applications. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+ (C) Copyright 2013-2014 Hewlett-Packard Development Company, L.P.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SHELL_COMMAND_LIB_ +#define _SHELL_COMMAND_LIB_ + +#include + +#include +#include +#include +#include + +#include + +// +// The extern global protocol poionters. +// +extern EFI_UNICODE_COLLATION_PROTOCOL *gUnicodeCollation; +extern CONST CHAR16* SupportLevel[]; + +// +// The map list objects. +// +typedef struct { + LIST_ENTRY Link; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + CHAR16 *MapName; + CHAR16 *CurrentDirectoryPath; + UINT64 Flags; +} SHELL_MAP_LIST; +/// List of Mappings - DeviceName and Drive Letter(ism). +extern SHELL_MAP_LIST gShellMapList; +/// Pointer to node of current directory in the mMapList. +extern SHELL_MAP_LIST *gShellCurMapping; + +/** + Returns the help MAN fileName for a given shell command. + + @retval !NULL The unicode string of the MAN filename. + @retval NULL An error ocurred. + +**/ +typedef +CONST CHAR16 * +(EFIAPI *SHELL_GET_MAN_FILENAME)( + VOID + ); + +/** + Runs a shell command on a given command line. + + The specific operation of a given shell command is specified in the UEFI Shell + Specification 2.0, or in the source of the given command. + + Upon completion of the command run the shell protocol and environment variables + may have been updated due to the operation. + + @param[in] ImageHandle The ImageHandle to the app, or NULL if + the command built into shell. + @param[in] SystemTable The pointer to the system table. + + @retval RETURN_SUCCESS The shell command was sucessful. + @retval RETURN_UNSUPPORTED The command is not supported. +**/ +typedef +SHELL_STATUS +(EFIAPI *SHELL_RUN_COMMAND)( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Registers the handlers of type SHELL_RUN_COMMAND and + SHELL_GET_MAN_FILENAME for each shell command. + + If the ShellSupportLevel is greater than the value of + PcdShellSupportLevel, then return RETURN_UNSUPPORTED. + + Registers the the handlers specified by GetHelpInfoHandler and CommandHandler + with the command specified by CommandString. If the command named by + CommandString has already been registered, then return + RETURN_ALREADY_STARTED. + + If there are not enough resources available to register the handlers, then + RETURN_OUT_OF_RESOURCES is returned. + + If CommandString is NULL, then ASSERT(). + If GetHelpInfoHandler is NULL, then ASSERT(). + If CommandHandler is NULL, then ASSERT(). + If ProfileName is NULL, then ASSERT(). + + @param[in] CommandString The pointer to the command name. This is the + name to look for on the command line in + the shell. + @param[in] CommandHandler The pointer to a function that runs the + specified command. + @param[in] GetManFileName The pointer to a function that provides man + filename. + @param[in] ShellMinSupportLevel The minimum Shell Support Level which has this + function. + @param[in] ProfileName The profile name to require for support of this + function. + @param[in] CanAffectLE Indicates whether this command's return value + can change the LASTERROR environment variable. + @param[in] HiiHandle The handle of this command's HII entry. + @param[in] ManFormatHelp The HII locator for the help text. + + @retval RETURN_SUCCESS The handlers were registered. + @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to + register the shell command. + @retval RETURN_UNSUPPORTED The ShellMinSupportLevel was higher than the + currently allowed support level. + @retval RETURN_ALREADY_STARTED The CommandString represents a command that + is already registered. Only one handler set for + a given command is allowed. + @sa SHELL_GET_MAN_FILENAME + @sa SHELL_RUN_COMMAND +**/ +RETURN_STATUS +EFIAPI +ShellCommandRegisterCommandName ( + IN CONST CHAR16 *CommandString, + IN SHELL_RUN_COMMAND CommandHandler, + IN SHELL_GET_MAN_FILENAME GetManFileName, + IN UINT32 ShellMinSupportLevel, + IN CONST CHAR16 *ProfileName, + IN CONST BOOLEAN CanAffectLE, + IN CONST EFI_HII_HANDLE HiiHandle, + IN CONST EFI_STRING_ID ManFormatHelp + ); + +/** + Checks if a command string has been registered for CommandString, and if so, it runs + the previously registered handler for that command with the command line. + + If CommandString is NULL, then ASSERT(). + + If Sections is specified, then each section name listed will be compared in a case sensitive + manner to the section names described in Appendix B UEFI Shell 2.0 Specification. If the section exists, + it is appended to the returned help text. If the section does not exist, no + information is returned. If Sections is NULL, then all help text information + available is returned. + + @param[in] CommandString The pointer to the command name. This is the name + found on the command line in the shell. + @param[in, out] RetVal The pointer to the return value from the command handler. + + @param[in, out] CanAffectLE Indicates whether this command's return value + needs to be placed into LASTERROR environment variable. + + @retval RETURN_SUCCESS The handler was run. + @retval RETURN_NOT_FOUND The CommandString did not match a registered + command name. + @sa SHELL_RUN_COMMAND +**/ +RETURN_STATUS +EFIAPI +ShellCommandRunCommandHandler ( + IN CONST CHAR16 *CommandString, + IN OUT SHELL_STATUS *RetVal, + IN OUT BOOLEAN *CanAffectLE OPTIONAL + ); + +/** + Checks if a command string has been registered for CommandString, and if so, it + returns the MAN filename specified for that command. + + If CommandString is NULL, then ASSERT(). + + @param[in] CommandString The pointer to the command name. This is the name + found on the command line in the shell. + + @retval NULL The CommandString was not a registered command. + @retval other The name of the MAN file. + @sa SHELL_GET_MAN_FILENAME +**/ +CONST CHAR16* +EFIAPI +ShellCommandGetManFileNameHandler ( + IN CONST CHAR16 *CommandString + ); + + +typedef struct { + LIST_ENTRY Link; + CHAR16 *CommandString; +} COMMAND_LIST; + +/** + Get the list of all available shell internal commands. This is a linked list, + via the LIST_ENTRY structure. Enumerate through it using the BaseLib linked + list functions. Do not modify the values. + + @param[in] Sort TRUE to alphabetically sort the values first. FALSE otherwise. + + @return A linked list of all available shell commands. +**/ +CONST COMMAND_LIST* +EFIAPI +ShellCommandGetCommandList ( + IN CONST BOOLEAN Sort + ); + +typedef struct { + LIST_ENTRY Link; + CHAR16 *CommandString; + CHAR16 *Alias; +} ALIAS_LIST; + +/** + Registers aliases to be set as part of the initialization of the shell application. + + If Command is NULL, then ASSERT(). + If Alias is NULL, then ASSERT(). + + @param[in] Command The pointer to the Command. + @param[in] Alias The pointer to Alias. + + @retval RETURN_SUCCESS The handlers were registered. + @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to + register the shell command. +**/ +RETURN_STATUS +EFIAPI +ShellCommandRegisterAlias ( + IN CONST CHAR16 *Command, + IN CONST CHAR16 *Alias + ); + +/** + Get the list of all shell alias commands. This is a linked list, + via LIST_ENTRY structure. Enumerate through it using the BaseLib linked + list functions. Do not modify the values. + + @return A linked list of all requested shell aliases. +**/ +CONST ALIAS_LIST* +EFIAPI +ShellCommandGetInitAliasList ( + VOID + ); + +/** + Determine if a given alias is on the list of built in aliases. + + @param[in] Alias The alias to test for. + + @retval TRUE The alias is a built in alias. + @retval FALSE The alias is not a built in alias. +**/ +BOOLEAN +EFIAPI +ShellCommandIsOnAliasList ( + IN CONST CHAR16 *Alias + ); + +/** + Checks if a command is already on the list. + + @param[in] CommandString The command string to check for on the list. + + @retval TRUE CommandString represents a registered command. + @retval FALSE CommandString does not represent a registered command. +**/ +BOOLEAN +EFIAPI +ShellCommandIsCommandOnList ( + IN CONST CHAR16 *CommandString + ); + +/** + Get the help text for a command. + + @param[in] CommandString The command name. + + @retval NULL No help text was found. + @return The string of the help text. The caller required to free. +**/ +CHAR16* +EFIAPI +ShellCommandGetCommandHelp ( + IN CONST CHAR16 *CommandString + ); + +/** + Function to make sure that the above pointers are valid. +**/ +EFI_STATUS +EFIAPI +CommandInit ( + VOID + ); + +/** + Function to determine current state of ECHO. Echo determines if lines from scripts + and ECHO commands are enabled. + + @retval TRUE Echo is currently enabled. + @retval FALSE Echo is currently disabled. +**/ +BOOLEAN +EFIAPI +ShellCommandGetEchoState ( + VOID + ); + +/** + Function to set current state of ECHO. Echo determines if lines from scripts + and ECHO commands are enabled. + + @param[in] State TRUE to enable Echo, FALSE otherwise. +**/ +VOID +EFIAPI +ShellCommandSetEchoState ( + IN BOOLEAN State + ); + + + +/** + Indicate that the current shell or script should exit. + + @param[in] ScriptOnly TRUE if exiting a script; FALSE otherwise. + @param[in] ErrorCode The 64 bit error code to return. +**/ +VOID +EFIAPI +ShellCommandRegisterExit ( + IN BOOLEAN ScriptOnly, + IN CONST UINT64 ErrorCode + ); + +/** + Retrieve the Exit code. + + @return the value passed into RegisterExit. +**/ +UINT64 +EFIAPI +ShellCommandGetExitCode ( + VOID + ); + +/** + Retrieve the Exit indicator. + + @retval TRUE Exit was indicated. + @retval FALSE Exit was not indicated. +**/ +BOOLEAN +EFIAPI +ShellCommandGetExit ( + VOID + ); + +/** + Retrieve the Exit script indicator. + + If ShellCommandGetExit returns FALSE, then the return from this is undefined. + + @retval TRUE ScriptOnly was indicated. + @retval FALSE ScriptOnly was not indicated. +**/ +BOOLEAN +EFIAPI +ShellCommandGetScriptExit ( + VOID + ); + +typedef struct { + LIST_ENTRY Link; ///< List enumerator items. + UINTN Line; ///< What line of the script file this was on. + CHAR16 *Cl; ///< The original command line. + VOID *Data; ///< The data structure format dependant upon Command. (not always used) + BOOLEAN Reset; ///< Reset the command (it must be treated like a initial run (but it may have data already)) +} SCRIPT_COMMAND_LIST; + +typedef struct { + CHAR16 *ScriptName; ///< The filename of this script. + CHAR16 **Argv; ///< The parmameters to the script file. + UINTN Argc; ///< The count of parameters. + LIST_ENTRY CommandList; ///< The script converted to a list of commands (SCRIPT_COMMAND_LIST objects). + SCRIPT_COMMAND_LIST *CurrentCommand; ///< The command currently being operated. If !=NULL must be a member of CommandList. + LIST_ENTRY SubstList; ///< A list of current script loop alias' (ALIAS_LIST objects) (Used for the for %-based replacement). +} SCRIPT_FILE; + +/** + Function to return a pointer to the currently running script file object. + + @retval NULL A script file is not currently running. + @return A pointer to the current script file object. +**/ +SCRIPT_FILE* +EFIAPI +ShellCommandGetCurrentScriptFile ( + VOID + ); + +/** + Function to set a new script as the currently running one. + + This function will correctly stack and unstack nested scripts. + + @param[in] Script The pointer to new script information structure. If NULL, + it removes and de-allocates the topmost Script structure. + + @return A pointer to the current running script file after this + change. It is NULL if removing the final script. +**/ +SCRIPT_FILE* +EFIAPI +ShellCommandSetNewScript ( + IN SCRIPT_FILE *Script OPTIONAL + ); + +/** + Function to cleanup all memory from a SCRIPT_FILE structure. + + @param[in] Script The pointer to the structure to cleanup. +**/ +VOID +EFIAPI +DeleteScriptFileStruct ( + IN SCRIPT_FILE *Script + ); + +/** + Function to get the current Profile string. + + This is used to retrieve what profiles were installed. + + @retval NULL There are no installed profiles. + @return A semicolon-delimited list of profiles. +**/ +CONST CHAR16 * +EFIAPI +ShellCommandGetProfileList ( + VOID + ); + +typedef enum { + MappingTypeFileSystem, + MappingTypeBlockIo, + MappingTypeMax +} SHELL_MAPPING_TYPE; + +/** + Function to generate the next default mapping name. + + If the return value is not NULL then it must be callee freed. + + @param Type What kind of mapping name to make. + + @retval NULL a memory allocation failed. + @return a new map name string +**/ +CHAR16* +EFIAPI +ShellCommandCreateNewMappingName( + IN CONST SHELL_MAPPING_TYPE Type + ); + +/** + Function to initialize the table for creating consistent map names. + + @param[out] Table The pointer to pointer to pointer to DevicePathProtocol object. + + @retval EFI_SUCCESS The table was created successfully. +**/ +EFI_STATUS +EFIAPI +ShellCommandConsistMappingInitialize ( + EFI_DEVICE_PATH_PROTOCOL ***Table + ); + +/** + Function to uninitialize the table for creating consistent map names. + + The parameter must have been received from ShellCommandConsistMappingInitialize. + + @param[out] Table The pointer to pointer to DevicePathProtocol object. + + @retval EFI_SUCCESS The table was deleted successfully. +**/ +EFI_STATUS +EFIAPI +ShellCommandConsistMappingUnInitialize ( + EFI_DEVICE_PATH_PROTOCOL **Table + ); + +/** + Create a consistent mapped name for the device specified by DevicePath + based on the Table. + + This must be called after ShellCommandConsistMappingInitialize() and + before ShellCommandConsistMappingUnInitialize() is called. + + @param[in] DevicePath The pointer to the dev path for the device. + @param[in] Table The Table of mapping information. + + @retval NULL A consistent mapped name could not be created. + @return A pointer to a string allocated from pool with the device name. +**/ +CHAR16* +EFIAPI +ShellCommandConsistMappingGenMappingName ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_DEVICE_PATH_PROTOCOL **Table + ); + +/** + Function to search the list of mappings for the first matching node on the + list based on the MapKey. + + @param[in] MapKey The pointer to the string key to search for in the map. + + @return the node on the list. +**/ +SHELL_MAP_LIST* +EFIAPI +ShellCommandFindMapItem ( + IN CONST CHAR16 *MapKey + ); + +/** + Function to add a map node to the list of map items and update the "path" environment variable (optionally). + + If Path is TRUE (during initialization only), the path environment variable will also be updated to include + default paths on the new map name... + + Path should be FALSE when this function is called from the protocol SetMap function. + + @param[in] Name The human readable mapped name. + @param[in] DevicePath The Device Path for this map. + @param[in] Flags The Flags attribute for this map item. + @param[in] Path TRUE to update path, FALSE to skip this step (should only be TRUE during initialization). + + @retval EFI_SUCCESS The addition was sucessful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_INVALID_PARAMETER A parameter was invalid. +**/ +EFI_STATUS +EFIAPI +ShellCommandAddMapItemAndUpdatePath( + IN CONST CHAR16 *Name, + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN CONST UINT64 Flags, + IN CONST BOOLEAN Path + ); + +/** + Creates the default map names for each device path in the system with + a protocol depending on the Type. + + Also sets up the default path environment variable if Type is FileSystem. + + @retval EFI_SUCCESS All map names were created sucessfully. + @retval EFI_NOT_FOUND No protocols were found in the system. + @return Error returned from gBS->LocateHandle(). + + @sa LocateHandle +**/ +EFI_STATUS +EFIAPI +ShellCommandCreateInitialMappingsAndPaths( + VOID + ); + +/** + Add mappings for any devices without one. Do not change any existing maps. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +ShellCommandUpdateMapping ( + VOID + ); + +/** + Converts a SHELL_FILE_HANDLE to an EFI_FILE_PROTOCOL*. + + @param[in] Handle The SHELL_FILE_HANDLE to convert. + + @return a EFI_FILE_PROTOCOL* representing the same file. +**/ +EFI_FILE_PROTOCOL* +EFIAPI +ConvertShellHandleToEfiFileProtocol( + IN CONST SHELL_FILE_HANDLE Handle + ); + +/** + Remove a SHELL_FILE_HANDLE frmo the list of SHELL_FILE_HANDLES. + + @param[in] Handle The SHELL_FILE_HANDLE to remove. + + @retval TRUE The item was removed. + @retval FALSE The item was not found. +**/ +BOOLEAN +EFIAPI +ShellFileHandleRemove( + IN CONST SHELL_FILE_HANDLE Handle + ); + +/** + Converts a EFI_FILE_PROTOCOL* to an SHELL_FILE_HANDLE. + + @param[in] Handle The pointer to EFI_FILE_PROTOCOL to convert. + @param[in] Path The path to the file for verification. + + @return a SHELL_FILE_HANDLE representing the same file. +**/ +SHELL_FILE_HANDLE +EFIAPI +ConvertEfiFileProtocolToShellHandle( + IN CONST EFI_FILE_PROTOCOL *Handle, + IN CONST CHAR16 *Path + ); + +/** + Find the path that was logged with the specified SHELL_FILE_HANDLE. + + @param[in] Handle The SHELL_FILE_HANDLE to query on. + + @return A pointer to the path for the file. +**/ +CONST CHAR16* +EFIAPI +ShellFileHandleGetPath( + IN CONST SHELL_FILE_HANDLE Handle + ); + + +/** + Function to determine if a SHELL_FILE_HANDLE is at the end of the file. + + This will NOT work on directories. + + If Handle is NULL, then ASSERT. + + @param[in] Handle the file handle + + @retval TRUE the position is at the end of the file + @retval FALSE the position is not at the end of the file +**/ +BOOLEAN +EFIAPI +ShellFileHandleEof( + IN SHELL_FILE_HANDLE Handle + ); + +typedef struct { + LIST_ENTRY Link; + void *Buffer; +} BUFFER_LIST; + +/** + Frees any BUFFER_LIST defined type. + + @param[in] List The pointer to the list head. +**/ +VOID +EFIAPI +FreeBufferList ( + IN BUFFER_LIST *List + ); + +/** + Function printing hex output to the console. + + @param[in] Indent Number of spaces to indent. + @param[in] Offset Offset to start with. + @param[in] DataSize Length of data. + @param[in] UserData Pointer to some data. +**/ +VOID +EFIAPI +DumpHex ( + IN UINTN Indent, + IN UINTN Offset, + IN UINTN DataSize, + IN VOID *UserData + ); + +/** + Dump HEX data into buffer. + + @param[in] Buffer HEX data to be dumped in Buffer. + @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. +**/ +CHAR16* +EFIAPI +CatSDumpHex ( + IN CHAR16 *Buffer, + IN UINTN Indent, + IN UINTN Offset, + IN UINTN DataSize, + IN VOID *UserData + ); + +// +// Determines the ordering operation for ShellSortFileList(). +// +typedef enum { + // + // Sort the EFI_SHELL_FILE_INFO objects by the FileName field, in increasing + // order, using gUnicodeCollation->StriColl(). + // + ShellSortFileListByFileName, + // + // Sort the EFI_SHELL_FILE_INFO objects by the FullName field, in increasing + // order, using gUnicodeCollation->StriColl(). + // + ShellSortFileListByFullName, + ShellSortFileListMax +} SHELL_SORT_FILE_LIST; + +/** + Sort an EFI_SHELL_FILE_INFO list, optionally moving duplicates to a separate + list. + + @param[in,out] FileList The list of EFI_SHELL_FILE_INFO objects to sort. + + If FileList is NULL on input, then FileList is + considered an empty, hence already sorted, list. + + Otherwise, if (*FileList) is NULL on input, then + EFI_INVALID_PARAMETER is returned. + + Otherwise, the caller is responsible for having + initialized (*FileList)->Link with + InitializeListHead(). No other fields in the + (**FileList) head element are accessed by this + function. + + On output, (*FileList) is sorted according to Order. + If Duplicates is NULL on input, then duplicate + elements are preserved, sorted stably, on + (*FileList). If Duplicates is not NULL on input, + then duplicates are moved (stably sorted) to the + new, dynamically allocated (*Duplicates) list. + + @param[out] Duplicates If Duplicates is NULL on input, (*FileList) will be + a monotonically ordered list on output, with + duplicates stably sorted. + + If Duplicates is not NULL on input, (*FileList) will + be a strictly monotonically oredered list on output, + with duplicates separated (stably sorted) to + (*Duplicates). All fields except Link will be + zero-initialized in the (**Duplicates) head element. + If no duplicates exist, then (*Duplicates) is set to + NULL on output. + + @param[in] Order Determines the comparison operation between + EFI_SHELL_FILE_INFO objects. + + @retval EFI_INVALID_PARAMETER (UINTN)Order is greater than or equal to + (UINTN)ShellSortFileListMax. Neither the + (*FileList) nor the (*Duplicates) list has + been modified. + + @retval EFI_INVALID_PARAMETER (*FileList) was NULL on input. Neither the + (*FileList) nor the (*Duplicates) list has + been modified. + + @retval EFI_OUT_OF_RESOURCES Memory allocation failed. Neither the + (*FileList) nor the (*Duplicates) list has + been modified. + + @retval EFI_SUCCESS Sorting successful, including the case when + FileList is NULL on input. +**/ +EFI_STATUS +EFIAPI +ShellSortFileList ( + IN OUT EFI_SHELL_FILE_INFO **FileList, + OUT EFI_SHELL_FILE_INFO **Duplicates OPTIONAL, + IN SHELL_SORT_FILE_LIST Order + ); +#endif //_SHELL_COMMAND_LIB_ diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Library/ShellLib.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Library/ShellLib.h new file mode 100644 index 00000000..94e4994d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Library/ShellLib.h @@ -0,0 +1,1432 @@ +/** @file + Provides interface to shell functionality for shell commands and applications. + + Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ Copyright 2018 Dell Technologies.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __SHELL_LIB__ +#define __SHELL_LIB__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define SHELL_FREE_NON_NULL(Pointer) \ + do { \ + if ((Pointer) != NULL) { \ + FreePool((Pointer)); \ + (Pointer) = NULL; \ + } \ + } while(FALSE) + +extern EFI_SHELL_PARAMETERS_PROTOCOL *gEfiShellParametersProtocol; +extern EFI_SHELL_PROTOCOL *gEfiShellProtocol; + +/** + Return a clean, fully-qualified version of an input path. If the return value + is non-NULL the caller must free the memory when it is no longer needed. + + If asserts are disabled, and if the input parameter is NULL, NULL is returned. + + If there is not enough memory available to create the fully-qualified path or + a copy of the input path, NULL is returned. + + If there is no working directory, a clean copy of Path is returned. + + Otherwise, the current file system or working directory (as appropriate) is + prepended to Path and the resulting path is cleaned and returned. + + NOTE: If the input path is an empty string, then the current working directory + (if it exists) is returned. In other words, an empty input path is treated + exactly the same as ".". + + @param[in] Path A pointer to some file or directory path. + + @retval NULL The input path is NULL or out of memory. + + @retval non-NULL A pointer to a clean, fully-qualified version of Path. + If there is no working directory, then a pointer to a + clean, but not necessarily fully-qualified version of + Path. The caller must free this memory when it is no + longer needed. +**/ +CHAR16* +EFIAPI +FullyQualifyPath( + IN CONST CHAR16 *Path + ); + +/** + This function will retrieve the information about the file for the handle + specified and store it in allocated pool memory. + + This function allocates a buffer to store the file's information. It is the + caller's responsibility to free the buffer. + + @param[in] FileHandle The file handle of the file for which information is + being requested. + + @retval NULL Information could not be retrieved. + + @return The information about the file. +**/ +EFI_FILE_INFO* +EFIAPI +ShellGetFileInfo ( + IN SHELL_FILE_HANDLE FileHandle + ); + +/** + This function sets the information about the file for the opened handle + specified. + + @param[in] FileHandle The file handle of the file for which information + is being set. + + @param[in] FileInfo The information to set. + + @retval EFI_SUCCESS The information was set. + @retval EFI_INVALID_PARAMETER A parameter was out of range or invalid. + @retval EFI_UNSUPPORTED The FileHandle does not support FileInfo. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The file or medium is write protected. + @retval EFI_ACCESS_DENIED The file was opened read only. + @retval EFI_VOLUME_FULL The volume is full. +**/ +EFI_STATUS +EFIAPI +ShellSetFileInfo ( + IN SHELL_FILE_HANDLE FileHandle, + IN EFI_FILE_INFO *FileInfo + ); + +/** + This function will open a file or directory referenced by DevicePath. + + This function opens a file with the open mode according to the file path. The + Attributes is valid only for EFI_FILE_MODE_CREATE. + + @param[in, out] FilePath On input, the device path to the file. On output, + the remaining device path. + @param[out] FileHandle Pointer to the file handle. + @param[in] OpenMode The mode to open the file with. + @param[in] Attributes The file's file attributes. + + @retval EFI_SUCCESS The information was set. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + @retval EFI_UNSUPPORTED Could not open the file path. + @retval EFI_NOT_FOUND The specified file could not be found on the + device or the file system could not be found on + the device. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_MEDIA_CHANGED The device has a different medium in it or the + medium is no longer supported. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The file or medium is write protected. + @retval EFI_ACCESS_DENIED The file was opened read only. + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the + file. + @retval EFI_VOLUME_FULL The volume is full. +**/ +EFI_STATUS +EFIAPI +ShellOpenFileByDevicePath( + IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, + OUT SHELL_FILE_HANDLE *FileHandle, + IN UINT64 OpenMode, + IN UINT64 Attributes + ); + +/** + This function will open a file or directory referenced by filename. + + If return is EFI_SUCCESS, the Filehandle is the opened file's handle; + otherwise, the Filehandle is NULL. Attributes is valid only for + EFI_FILE_MODE_CREATE. + + @param[in] FileName The pointer to file name. + @param[out] FileHandle The pointer to the file handle. + @param[in] OpenMode The mode to open the file with. + @param[in] Attributes The file's file attributes. + + @retval EFI_SUCCESS The information was set. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + @retval EFI_UNSUPPORTED Could not open the file path. + @retval EFI_NOT_FOUND The specified file could not be found on the + device or the file system could not be found + on the device. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_MEDIA_CHANGED The device has a different medium in it or the + medium is no longer supported. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The file or medium is write protected. + @retval EFI_ACCESS_DENIED The file was opened read only. + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the + file. + @retval EFI_VOLUME_FULL The volume is full. +**/ +EFI_STATUS +EFIAPI +ShellOpenFileByName( + IN CONST CHAR16 *FileName, + OUT SHELL_FILE_HANDLE *FileHandle, + IN UINT64 OpenMode, + IN UINT64 Attributes + ); + +/** + This function creates a directory. + + If return is EFI_SUCCESS, the Filehandle is the opened directory's handle; + otherwise, the Filehandle is NULL. If the directory already existed, this + function opens the existing directory. + + @param[in] DirectoryName The pointer to Directory name. + @param[out] FileHandle The pointer to the file handle. + + @retval EFI_SUCCESS The information was set. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + @retval EFI_UNSUPPORTED Could not open the file path. + @retval EFI_NOT_FOUND The specified file could not be found on the + device, or the file system could not be found + on the device. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_MEDIA_CHANGED The device has a different medium in it or the + medium is no longer supported. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The file or medium is write protected. + @retval EFI_ACCESS_DENIED The file was opened read only. + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the + file. + @retval EFI_VOLUME_FULL The volume is full. +**/ +EFI_STATUS +EFIAPI +ShellCreateDirectory( + IN CONST CHAR16 *DirectoryName, + OUT SHELL_FILE_HANDLE *FileHandle + ); + +/** + This function reads information from an opened file. + + If FileHandle is not a directory, the function reads the requested number of + bytes from the file at the file's current position and returns them in Buffer. + If the read goes beyond the end of the file, the read length is truncated to the + end of the file. The file's current position is increased by the number of bytes + returned. If FileHandle is a directory, the function reads the directory entry + at the file's current position and returns the entry in Buffer. If the Buffer + is not large enough to hold the current directory entry, then + EFI_BUFFER_TOO_SMALL is returned and the current file position is not updated. + BufferSize is set to be the size of the buffer needed to read the entry. On + success, the current position is updated to the next directory entry. If there + are no more directory entries, the read returns a zero-length buffer. + EFI_FILE_INFO is the structure returned as the directory entry. + + @param[in] FileHandle The opened file handle. + @param[in, out] ReadSize On input the size of buffer in bytes. On return + the number of bytes written. + @param[out] Buffer The buffer to put read data into. + + @retval EFI_SUCCESS Data was read. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_BUFFER_TO_SMALL Buffer is too small. ReadSize contains required + size. + +**/ +EFI_STATUS +EFIAPI +ShellReadFile( + IN SHELL_FILE_HANDLE FileHandle, + IN OUT UINTN *ReadSize, + OUT VOID *Buffer + ); + +/** + Write data to a file. + + This function writes the specified number of bytes to the file at the current + file position. The current file position is advanced the actual number of bytes + written, which is returned in BufferSize. Partial writes only occur when there + has been a data error during the write attempt (such as "volume space full"). + The file is automatically grown to hold the data if required. Direct writes to + opened directories are not supported. + + @param[in] FileHandle The opened file for writing. + + @param[in, out] BufferSize On input the number of bytes in Buffer. On output + the number of bytes written. + + @param[in] Buffer The buffer containing data to write is stored. + + @retval EFI_SUCCESS Data was written. + @retval EFI_UNSUPPORTED Writes to an open directory are not supported. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The device is write-protected. + @retval EFI_ACCESS_DENIED The file was open for read only. + @retval EFI_VOLUME_FULL The volume is full. +**/ +EFI_STATUS +EFIAPI +ShellWriteFile( + IN SHELL_FILE_HANDLE FileHandle, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ); + +/** + Close an open file handle. + + This function closes a specified file handle. All "dirty" cached file data is + flushed to the device, and the file is closed. In all cases the handle is + closed. + + @param[in] FileHandle The file handle to close. + + @retval EFI_SUCCESS The file handle was closed sucessfully. + @retval INVALID_PARAMETER One of the parameters has an invalid value. +**/ +EFI_STATUS +EFIAPI +ShellCloseFile ( + IN SHELL_FILE_HANDLE *FileHandle + ); + +/** + Delete a file and close the handle + + This function closes and deletes a file. In all cases the file handle is closed. + If the file cannot be deleted, the warning code EFI_WARN_DELETE_FAILURE is + returned, but the handle is still closed. + + @param[in] FileHandle The file handle to delete. + + @retval EFI_SUCCESS The file was closed sucessfully. + @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not + deleted. + @retval INVALID_PARAMETER One of the parameters has an invalid value. +**/ +EFI_STATUS +EFIAPI +ShellDeleteFile ( + IN SHELL_FILE_HANDLE *FileHandle + ); + +/** + Set the current position in a file. + + This function sets the current file position for the handle to the position + supplied. With the exception of seeking to position 0xFFFFFFFFFFFFFFFF, only + absolute positioning is supported, and moving past the end of the file is + allowed (a subsequent write would grow the file). Moving to position + 0xFFFFFFFFFFFFFFFF causes the current position to be set to the end of the file. + If FileHandle is a directory, the only position that may be set is zero. This + has the effect of starting the read process of the directory entries over. + + @param[in] FileHandle The file handle on which the position is being set. + + @param[in] Position The byte position from the begining of the file. + + @retval EFI_SUCCESS Operation completed sucessfully. + @retval EFI_UNSUPPORTED The seek request for non-zero is not valid on + directories. + @retval INVALID_PARAMETER One of the parameters has an invalid value. +**/ +EFI_STATUS +EFIAPI +ShellSetFilePosition ( + IN SHELL_FILE_HANDLE FileHandle, + IN UINT64 Position + ); + +/** + Gets a file's current position + + This function retrieves the current file position for the file handle. For + directories, the current file position has no meaning outside of the file + system driver and as such the operation is not supported. An error is returned + if FileHandle is a directory. + + @param[in] FileHandle The open file handle on which to get the position. + @param[out] Position The byte position from the begining of the file. + + @retval EFI_SUCCESS The operation completed sucessfully. + @retval INVALID_PARAMETER One of the parameters has an invalid value. + @retval EFI_UNSUPPORTED The request is not valid on directories. +**/ +EFI_STATUS +EFIAPI +ShellGetFilePosition ( + IN SHELL_FILE_HANDLE FileHandle, + OUT UINT64 *Position + ); + +/** + Flushes data on a file + + This function flushes all modified data associated with a file to a device. + + @param[in] FileHandle The file handle on which to flush data. + + @retval EFI_SUCCESS The data was flushed. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The file or medium is write protected. + @retval EFI_ACCESS_DENIED The file was opened for read only. +**/ +EFI_STATUS +EFIAPI +ShellFlushFile ( + IN SHELL_FILE_HANDLE FileHandle + ); + +/** Retrieve first entry from a directory. + + This function takes an open directory handle and gets information from the + first entry in the directory. A buffer is allocated to contain + the information and a pointer to the buffer is returned in *Buffer. The + caller can use ShellFindNextFile() to get subsequent directory entries. + + The buffer will be freed by ShellFindNextFile() when the last directory + entry is read. Otherwise, the caller must free the buffer, using FreePool, + when finished with it. + + @param[in] DirHandle The file handle of the directory to search. + @param[out] Buffer The pointer to the buffer for the file's information. + + @retval EFI_SUCCESS Found the first file. + @retval EFI_NOT_FOUND Cannot find the directory. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @return Others Status of ShellGetFileInfo, ShellSetFilePosition, + or ShellReadFile. + + @sa ShellReadFile +**/ +EFI_STATUS +EFIAPI +ShellFindFirstFile ( + IN SHELL_FILE_HANDLE DirHandle, + OUT EFI_FILE_INFO **Buffer + ); + +/** Retrieve next entries from a directory. + + To use this function, the caller must first call the ShellFindFirstFile() + function to get the first directory entry. Subsequent directory entries are + retrieved by using the ShellFindNextFile() function. This function can + be called several times to get each entry from the directory. If the call of + ShellFindNextFile() retrieved the last directory entry, the next call of + this function will set *NoFile to TRUE and free the buffer. + + @param[in] DirHandle The file handle of the directory. + @param[in, out] Buffer The pointer to buffer for file's information. + @param[in, out] NoFile The pointer to boolean when last file is found. + + @retval EFI_SUCCESS Found the next file. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + + @sa ShellReadFile +**/ +EFI_STATUS +EFIAPI +ShellFindNextFile( + IN SHELL_FILE_HANDLE DirHandle, + IN OUT EFI_FILE_INFO *Buffer, + IN OUT BOOLEAN *NoFile + ); + +/** + Retrieve the size of a file. + + This function extracts the file size info from the FileHandle's EFI_FILE_INFO + data. + + @param[in] FileHandle The file handle from which size is retrieved. + @param[out] Size The pointer to size. + + @retval EFI_SUCCESS The operation was completed sucessfully. + @retval EFI_DEVICE_ERROR Cannot access the file. +**/ +EFI_STATUS +EFIAPI +ShellGetFileSize ( + IN SHELL_FILE_HANDLE FileHandle, + OUT UINT64 *Size + ); + +/** + Retrieves the status of the break execution flag + + This function is useful to check whether the application is being asked to halt by the shell. + + @retval TRUE The execution break is enabled. + @retval FALSE The execution break is not enabled. +**/ +BOOLEAN +EFIAPI +ShellGetExecutionBreakFlag( + VOID + ); + +/** + Return the value of an environment variable. + + This function gets the value of the environment variable set by the + ShellSetEnvironmentVariable function. + + @param[in] EnvKey The key name of the environment variable. + + @retval NULL The named environment variable does not exist. + @return != NULL The pointer to the value of the environment variable. +**/ +CONST CHAR16* +EFIAPI +ShellGetEnvironmentVariable ( + IN CONST CHAR16 *EnvKey + ); + +/** + Set the value of an environment variable. + + This function changes the current value of the specified environment variable. If the + environment variable exists and the Value is an empty string, then the environment + variable is deleted. If the environment variable exists and the Value is not an empty + string, then the value of the environment variable is changed. If the environment + variable does not exist and the Value is an empty string, there is no action. If the + environment variable does not exist and the Value is a non-empty string, then the + environment variable is created and assigned the specified value. + + This is not supported pre-UEFI Shell 2.0. + + @param[in] EnvKey The key name of the environment variable. + @param[in] EnvVal The Value of the environment variable + @param[in] Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE). + + @retval EFI_SUCCESS The operation completed sucessfully + @retval EFI_UNSUPPORTED This operation is not allowed in pre-UEFI 2.0 Shell environments. +**/ +EFI_STATUS +EFIAPI +ShellSetEnvironmentVariable ( + IN CONST CHAR16 *EnvKey, + IN CONST CHAR16 *EnvVal, + IN BOOLEAN Volatile + ); + +/** + Cause the shell to parse and execute a command line. + + This function creates a nested instance of the shell and executes the specified + command (CommandLine) with the specified environment (Environment). Upon return, + the status code returned by the specified command is placed in StatusCode. + If Environment is NULL, then the current environment is used and all changes made + by the commands executed will be reflected in the current environment. If the + Environment is non-NULL, then the changes made will be discarded. + The CommandLine is executed from the current working directory on the current + device. + + The EnvironmentVariables and Status parameters are ignored in a pre-UEFI Shell 2.0 + environment. The values pointed to by the parameters will be unchanged by the + ShellExecute() function. The Output parameter has no effect in a + UEFI Shell 2.0 environment. + + @param[in] ParentHandle The parent image starting the operation. + @param[in] CommandLine The pointer to a NULL terminated command line. + @param[in] Output True to display debug output. False to hide it. + @param[in] EnvironmentVariables Optional pointer to array of environment variables + in the form "x=y". If NULL, the current set is used. + @param[out] Status The status of the run command line. + + @retval EFI_SUCCESS The operation completed sucessfully. Status + contains the status code returned. + @retval EFI_INVALID_PARAMETER A parameter contains an invalid value. + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_UNSUPPORTED The operation is not allowed. +**/ +EFI_STATUS +EFIAPI +ShellExecute ( + IN EFI_HANDLE *ParentHandle, + IN CHAR16 *CommandLine, + IN BOOLEAN Output, + IN CHAR16 **EnvironmentVariables, + OUT EFI_STATUS *Status + ); + +/** + Retreives the current directory path. + + If the DeviceName is NULL, it returns the current device's current directory + name. If the DeviceName is not NULL, it returns the current directory name + on specified drive. + + Note that the current directory string should exclude the tailing backslash character. + + @param[in] DeviceName The name of the file system to get directory on. + + @retval NULL The directory does not exist. + @retval != NULL The directory. +**/ +CONST CHAR16* +EFIAPI +ShellGetCurrentDir ( + IN CHAR16 * CONST DeviceName OPTIONAL + ); + +/** + Sets (enabled or disabled) the page break mode. + + When page break mode is enabled the screen will stop scrolling + and wait for operator input before scrolling a subsequent screen. + + @param[in] CurrentState TRUE to enable and FALSE to disable. +**/ +VOID +EFIAPI +ShellSetPageBreakMode ( + IN BOOLEAN CurrentState + ); + +/** + Opens a group of files based on a path. + + This function uses the Arg to open all the matching files. Each matched + file has a SHELL_FILE_ARG structure to record the file information. These + structures are placed on the list ListHead. Users can get the SHELL_FILE_ARG + structures from ListHead to access each file. This function supports wildcards + and will process '?' and '*' as such. The list must be freed with a call to + ShellCloseFileMetaArg(). + + If you are NOT appending to an existing list *ListHead must be NULL. If + *ListHead is NULL then it must be callee freed. + + @param[in] Arg The pointer to path string. + @param[in] OpenMode Mode to open files with. + @param[in, out] ListHead Head of linked list of results. + + @retval EFI_SUCCESS The operation was sucessful and the list head + contains the list of opened files. + @retval != EFI_SUCCESS The operation failed. + + @sa InternalShellConvertFileListType +**/ +EFI_STATUS +EFIAPI +ShellOpenFileMetaArg ( + IN CHAR16 *Arg, + IN UINT64 OpenMode, + IN OUT EFI_SHELL_FILE_INFO **ListHead + ); + +/** + Free the linked list returned from ShellOpenFileMetaArg. + + @param[in, out] ListHead The pointer to free. + + @retval EFI_SUCCESS The operation was sucessful. + @retval EFI_INVALID_PARAMETER A parameter was invalid. +**/ +EFI_STATUS +EFIAPI +ShellCloseFileMetaArg ( + IN OUT EFI_SHELL_FILE_INFO **ListHead + ); + +/** + Find a file by searching the CWD and then the path. + + If FileName is NULL, then ASSERT. + + If the return value is not NULL then the memory must be caller freed. + + @param[in] FileName Filename string. + + @retval NULL The file was not found. + @retval !NULL The path to the file. +**/ +CHAR16 * +EFIAPI +ShellFindFilePath ( + IN CONST CHAR16 *FileName + ); + +/** + Find a file by searching the CWD and then the path with a variable set of file + extensions. If the file is not found it will append each extension in the list + in the order provided and return the first one that is successful. + + If FileName is NULL, then ASSERT. + If FileExtension is NULL, then the behavior is identical to ShellFindFilePath. + + If the return value is not NULL then the memory must be caller freed. + + @param[in] FileName The filename string. + @param[in] FileExtension Semicolon delimited list of possible extensions. + + @retval NULL The file was not found. + @retval !NULL The path to the file. +**/ +CHAR16 * +EFIAPI +ShellFindFilePathEx ( + IN CONST CHAR16 *FileName, + IN CONST CHAR16 *FileExtension + ); + +typedef enum { + TypeFlag = 0, ///< A flag that is present or not present only (IE "-a"). + TypeValue, ///< A flag that has some data following it with a space (IE "-a 1"). + TypePosition, ///< Some data that did not follow a parameter (IE "filename.txt"). + TypeStart, ///< A flag that has variable value appended to the end (IE "-ad", "-afd", "-adf", etc...). + TypeDoubleValue, ///< A flag that has 2 space seperated value data following it (IE "-a 1 2"). + TypeMaxValue, ///< A flag followed by all the command line data before the next flag. + TypeTimeValue, ///< A flag that has a time value following it (IE "-a -5:00"). + TypeMax, +} SHELL_PARAM_TYPE; + +typedef struct { + CHAR16 *Name; + SHELL_PARAM_TYPE Type; +} SHELL_PARAM_ITEM; + + +/// Helper structure for no parameters (besides -? and -b) +extern SHELL_PARAM_ITEM EmptyParamList[]; + +/// Helper structure for -sfo only (besides -? and -b) +extern SHELL_PARAM_ITEM SfoParamList[]; + +/** + Checks the command line arguments passed against the list of valid ones. + Optionally removes NULL values first. + + If no initialization is required, then return RETURN_SUCCESS. + + @param[in] CheckList The pointer to list of parameters to check. + @param[out] CheckPackage The package of checked values. + @param[out] ProblemParam Optional pointer to pointer to unicode string for + the paramater that caused failure. + @param[in] AutoPageBreak Will automatically set PageBreakEnabled. + @param[in] AlwaysAllowNumbers Will never fail for number based flags. + + @retval EFI_SUCCESS The operation completed sucessfully. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_INVALID_PARAMETER A parameter was invalid. + @retval EFI_VOLUME_CORRUPTED The command line was corrupt. + @retval EFI_DEVICE_ERROR The commands contained 2 opposing arguments. One + of the command line arguments was returned in + ProblemParam if provided. + @retval EFI_NOT_FOUND A argument required a value that was missing. + The invalid command line argument was returned in + ProblemParam if provided. +**/ +EFI_STATUS +EFIAPI +ShellCommandLineParseEx ( + IN CONST SHELL_PARAM_ITEM *CheckList, + OUT LIST_ENTRY **CheckPackage, + OUT CHAR16 **ProblemParam OPTIONAL, + IN BOOLEAN AutoPageBreak, + IN BOOLEAN AlwaysAllowNumbers + ); + +/// Make it easy to upgrade from older versions of the shell library. +#define ShellCommandLineParse(CheckList,CheckPackage,ProblemParam,AutoPageBreak) ShellCommandLineParseEx(CheckList,CheckPackage,ProblemParam,AutoPageBreak,FALSE) + +/** + Frees shell variable list that was returned from ShellCommandLineParse. + + This function will free all the memory that was used for the CheckPackage + list of postprocessed shell arguments. + + If CheckPackage is NULL, then return. + + @param[in] CheckPackage The list to de-allocate. + **/ +VOID +EFIAPI +ShellCommandLineFreeVarList ( + IN LIST_ENTRY *CheckPackage + ); + +/** + Checks for presence of a flag parameter. + + Flag arguments are in the form of "-" or "/", but do not have a value following the key. + + If CheckPackage is NULL then return FALSE. + If KeyString is NULL then ASSERT(). + + @param[in] CheckPackage The package of parsed command line arguments. + @param[in] KeyString The Key of the command line argument to check for. + + @retval TRUE The flag is on the command line. + @retval FALSE The flag is not on the command line. +**/ +BOOLEAN +EFIAPI +ShellCommandLineGetFlag ( + IN CONST LIST_ENTRY * CONST CheckPackage, + IN CONST CHAR16 * CONST KeyString + ); + +/** + Returns value from command line argument. + + Value parameters are in the form of "- value" or "/ value". + + If CheckPackage is NULL, then return NULL. + + @param[in] CheckPackage The package of parsed command line arguments. + @param[in] KeyString The Key of the command line argument to check for. + + @retval NULL The flag is not on the command line. + @retval !=NULL The pointer to unicode string of the value. +**/ +CONST CHAR16* +EFIAPI +ShellCommandLineGetValue ( + IN CONST LIST_ENTRY *CheckPackage, + IN CHAR16 *KeyString + ); + +/** + Returns raw value from command line argument. + + Raw value parameters are in the form of "value" in a specific position in the list. + + If CheckPackage is NULL, then return NULL. + + @param[in] CheckPackage The package of parsed command line arguments. + @param[in] Position The position of the value. + + @retval NULL The flag is not on the command line. + @retval !=NULL The pointer to unicode string of the value. +**/ +CONST CHAR16* +EFIAPI +ShellCommandLineGetRawValue ( + IN CONST LIST_ENTRY * CONST CheckPackage, + IN UINTN Position + ); + +/** + Returns the number of command line value parameters that were parsed. + + This will not include flags. + + @param[in] CheckPackage The package of parsed command line arguments. + + @retval (UINTN)-1 No parsing has occurred. + @retval other The number of value parameters found. +**/ +UINTN +EFIAPI +ShellCommandLineGetCount( + IN CONST LIST_ENTRY *CheckPackage + ); + +/** + Determines if a parameter is duplicated. + + If Param is not NULL, then it will point to a callee-allocated string buffer + with the parameter value, if a duplicate is found. + + If CheckPackage is NULL, then ASSERT. + + @param[in] CheckPackage The package of parsed command line arguments. + @param[out] Param Upon finding one, a pointer to the duplicated parameter. + + @retval EFI_SUCCESS No parameters were duplicated. + @retval EFI_DEVICE_ERROR A duplicate was found. + **/ +EFI_STATUS +EFIAPI +ShellCommandLineCheckDuplicate ( + IN CONST LIST_ENTRY *CheckPackage, + OUT CHAR16 **Param + ); + +/** + This function causes the shell library to initialize itself. If the shell library + is already initialized it will de-initialize all the current protocol pointers and + re-populate them again. + + When the library is used with PcdShellLibAutoInitialize set to true this function + will return EFI_SUCCESS and perform no actions. + + This function is intended for internal access for shell commands only. + + @retval EFI_SUCCESS The initialization was complete sucessfully. + +**/ +EFI_STATUS +EFIAPI +ShellInitialize ( + VOID + ); + +/** + Print at a specific location on the screen. + + This function will move the cursor to a given screen location and print the specified string. + + If -1 is specified for either the Row or Col the current screen location for BOTH + will be used. + + If either Row or Col is out of range for the current console, then ASSERT. + If Format is NULL, then ASSERT. + + In addition to the standard %-based flags as supported by UefiLib Print() this supports + the following additional flags: + %N - Set output attribute to normal + %H - Set output attribute to highlight + %E - Set output attribute to error + %B - Set output attribute to blue color + %V - Set output attribute to green color + + Note: The background color is controlled by the shell command cls. + + @param[in] Col The column to print at. + @param[in] Row The row to print at. + @param[in] Format The format string. + @param[in] ... The variable argument list. + + @return EFI_SUCCESS The printing was successful. + @return EFI_DEVICE_ERROR The console device reported an error. +**/ +EFI_STATUS +EFIAPI +ShellPrintEx( + IN INT32 Col OPTIONAL, + IN INT32 Row OPTIONAL, + IN CONST CHAR16 *Format, + ... + ); + +/** + Print at a specific location on the screen. + + This function will move the cursor to a given screen location and print the specified string. + + If -1 is specified for either the Row or Col the current screen location for BOTH + will be used. + + If either Row or Col is out of range for the current console, then ASSERT. + If Format is NULL, then ASSERT. + + In addition to the standard %-based flags as supported by UefiLib Print() this supports + the following additional flags: + %N - Set output attribute to normal. + %H - Set output attribute to highlight. + %E - Set output attribute to error. + %B - Set output attribute to blue color. + %V - Set output attribute to green color. + + Note: The background color is controlled by the shell command cls. + + @param[in] Col The column to print at. + @param[in] Row The row to print at. + @param[in] Language The language of the string to retrieve. If this parameter + is NULL, then the current platform language is used. + @param[in] HiiFormatStringId The format string Id for getting from Hii. + @param[in] HiiFormatHandle The format string Handle for getting from Hii. + @param[in] ... The variable argument list. + + @return EFI_SUCCESS The printing was successful. + @return EFI_DEVICE_ERROR The console device reported an error. +**/ +EFI_STATUS +EFIAPI +ShellPrintHiiEx( + IN INT32 Col OPTIONAL, + IN INT32 Row OPTIONAL, + IN CONST CHAR8 *Language OPTIONAL, + IN CONST EFI_STRING_ID HiiFormatStringId, + IN CONST EFI_HII_HANDLE HiiFormatHandle, + ... + ); + +/** + Function to determine if a given filename represents a directory. + + If DirName is NULL, then ASSERT. + + @param[in] DirName Path to directory to test. + + @retval EFI_SUCCESS The Path represents a directory. + @retval EFI_NOT_FOUND The Path does not represent a directory. + @retval other The path failed to open. +**/ +EFI_STATUS +EFIAPI +ShellIsDirectory( + IN CONST CHAR16 *DirName + ); + +/** + Function to determine if a given filename represents a file. + + This will search the CWD only. + + If Name is NULL, then ASSERT. + + @param[in] Name Path to file to test. + + @retval EFI_SUCCESS The Path represents a file. + @retval EFI_NOT_FOUND The Path does not represent a file. + @retval other The path failed to open. +**/ +EFI_STATUS +EFIAPI +ShellIsFile( + IN CONST CHAR16 *Name + ); + +/** + Function to determine if a given filename represents a file. + + This will search the CWD and then the Path. + + If Name is NULL, then ASSERT. + + @param[in] Name Path to file to test. + + @retval EFI_SUCCESS The Path represents a file. + @retval EFI_NOT_FOUND The Path does not represent a file. + @retval other The path failed to open. +**/ +EFI_STATUS +EFIAPI +ShellIsFileInPath( + IN CONST CHAR16 *Name + ); + +/** + Function to determine whether a string is decimal or hex representation of a number + and return the number converted from the string. + + Note: this function cannot be used when (UINTN)(-1), (0xFFFFFFFF) may be a valid + result. Use ShellConvertStringToUint64 instead. + + @param[in] String String representation of a number. + + @return The unsigned integer result of the conversion. + @retval (UINTN)(-1) An error occurred. +**/ +UINTN +EFIAPI +ShellStrToUintn( + IN CONST CHAR16 *String + ); + +/** + Function return the number converted from a hex representation of a number. + + Note: this function cannot be used when (UINTN)(-1), (0xFFFFFFFF) may be a valid + result. Use ShellConvertStringToUint64 instead. + + @param[in] String String representation of a number. + + @return The unsigned integer result of the conversion. + @retval (UINTN)(-1) An error occurred. +**/ +UINTN +EFIAPI +ShellHexStrToUintn( + IN CONST CHAR16 *String + ); + +/** + 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, so return the current buffer in + Destination. + + If Destination is NULL, then ASSERT(). + If Destination's current length (including NULL terminator) is already more than + 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. + @param[in] Count The maximum number of characters to append. If 0, then + all are appended. + + @return The Destination after appending the Source. +**/ +CHAR16* +EFIAPI +StrnCatGrow ( + IN OUT CHAR16 **Destination, + IN OUT UINTN *CurrentSize, + IN CONST CHAR16 *Source, + IN UINTN Count + ); + +/** + This is a find and replace function. Upon successful return the NewString is a copy of + SourceString with each instance of FindTarget replaced with ReplaceWith. + + If SourceString and NewString overlap the behavior is undefined. + + If the string would grow bigger than NewSize it will halt and return error. + + @param[in] SourceString The string with source buffer. + @param[in, out] NewString The string with resultant buffer. + @param[in] NewSize The size in bytes of NewString. + @param[in] FindTarget The string to look for. + @param[in] ReplaceWith The string to replace FindTarget with. + @param[in] SkipPreCarrot If TRUE will skip a FindTarget that has a '^' + immediately before it. + @param[in] ParameterReplacing If TRUE will add "" around items with spaces. + + @retval EFI_INVALID_PARAMETER SourceString was NULL. + @retval EFI_INVALID_PARAMETER NewString was NULL. + @retval EFI_INVALID_PARAMETER FindTarget was NULL. + @retval EFI_INVALID_PARAMETER ReplaceWith was NULL. + @retval EFI_INVALID_PARAMETER FindTarget had length < 1. + @retval EFI_INVALID_PARAMETER SourceString had length < 1. + @retval EFI_BUFFER_TOO_SMALL NewSize was less than the minimum size to hold + the new string (truncation occurred). + @retval EFI_SUCCESS The string was successfully copied with replacement. +**/ +EFI_STATUS +EFIAPI +ShellCopySearchAndReplace( + IN CHAR16 CONST *SourceString, + IN OUT CHAR16 *NewString, + IN UINTN NewSize, + IN CONST CHAR16 *FindTarget, + IN CONST CHAR16 *ReplaceWith, + IN CONST BOOLEAN SkipPreCarrot, + IN CONST BOOLEAN ParameterReplacing + ); + +/** + Check if a Unicode character is a hexadecimal character. + + This internal function checks if a Unicode character is a + numeric character. The valid hexadecimal characters are + L'0' to L'9', L'a' to L'f', or L'A' to L'F'. + + + @param Char The character to check against. + + @retval TRUE The Char is a hexadecmial character. + @retval FALSE The Char is not a hexadecmial character. + +**/ +BOOLEAN +EFIAPI +ShellIsHexaDecimalDigitCharacter ( + IN CHAR16 Char + ); + +/** + Check if a Unicode character is a decimal character. + + This internal function checks if a Unicode character is a + decimal character. The valid characters are + L'0' to L'9'. + + + @param Char The character to check against. + + @retval TRUE The Char is a hexadecmial character. + @retval FALSE The Char is not a hexadecmial character. + +**/ +BOOLEAN +EFIAPI +ShellIsDecimalDigitCharacter ( + IN CHAR16 Char + ); + +/// +/// What type of answer is requested. +/// +typedef enum { + ShellPromptResponseTypeYesNo, + ShellPromptResponseTypeYesNoCancel, + ShellPromptResponseTypeFreeform, + ShellPromptResponseTypeQuitContinue, + ShellPromptResponseTypeYesNoAllCancel, + ShellPromptResponseTypeEnterContinue, + ShellPromptResponseTypeAnyKeyContinue, + ShellPromptResponseTypeMax +} SHELL_PROMPT_REQUEST_TYPE; + +/// +/// What answer was given. +/// +typedef enum { + ShellPromptResponseYes, + ShellPromptResponseNo, + ShellPromptResponseCancel, + ShellPromptResponseQuit, + ShellPromptResponseContinue, + ShellPromptResponseAll, + ShellPromptResponseMax +} SHELL_PROMPT_RESPONSE; + +/** + Prompt the user and return the resultant answer to the requestor. + + This function will display the requested question on the shell prompt and then + wait for an appropriate answer to be input from the console. + + If the SHELL_PROMPT_REQUEST_TYPE is SHELL_PROMPT_REQUEST_TYPE_YESNO, ShellPromptResponseTypeQuitContinue + or SHELL_PROMPT_REQUEST_TYPE_YESNOCANCEL then *Response is of type SHELL_PROMPT_RESPONSE. + + If the SHELL_PROMPT_REQUEST_TYPE is ShellPromptResponseTypeFreeform then *Response is of type + CHAR16*. + + In either case *Response must be callee freed if Response was not NULL; + + @param Type What type of question is asked. This is used to filter the input + to prevent invalid answers to question. + @param Prompt The pointer to a string prompt used to request input. + @param Response The pointer to Response, which will be populated upon return. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_UNSUPPORTED The operation is not supported as requested. + @retval EFI_INVALID_PARAMETER A parameter was invalid. + @return other The operation failed. +**/ +EFI_STATUS +EFIAPI +ShellPromptForResponse ( + IN SHELL_PROMPT_REQUEST_TYPE Type, + IN CHAR16 *Prompt OPTIONAL, + IN OUT VOID **Response OPTIONAL + ); + +/** + Prompt the user and return the resultant answer to the requestor. + + This function is the same as ShellPromptForResponse, except that the prompt is + automatically pulled from HII. + + @param[in] Type What type of question is asked. This is used to filter the input + to prevent invalid answers to question. + @param[in] HiiFormatStringId The format string Id for getting from Hii. + @param[in] HiiFormatHandle The format string Handle for getting from Hii. + @param[in, out] Response The pointer to Response, which will be populated upon return. + + @retval EFI_SUCCESS The operation was sucessful. + @return other The operation failed. + + @sa ShellPromptForResponse +**/ +EFI_STATUS +EFIAPI +ShellPromptForResponseHii ( + IN SHELL_PROMPT_REQUEST_TYPE Type, + IN CONST EFI_STRING_ID HiiFormatStringId, + IN CONST EFI_HII_HANDLE HiiFormatHandle, + IN OUT VOID **Response + ); + +/** + Function to determin if an entire string is a valid number. + + If Hex it must be preceeded with a 0x, 0X, or has ForceHex set TRUE. + + @param[in] String The string to evaluate. + @param[in] ForceHex TRUE - always assume hex. + @param[in] StopAtSpace TRUE to halt upon finding a space, FALSE to keep going. + + @retval TRUE It is all numeric (dec/hex) characters. + @retval FALSE There is a non-numeric character. +**/ +BOOLEAN +EFIAPI +ShellIsHexOrDecimalNumber ( + IN CONST CHAR16 *String, + IN CONST BOOLEAN ForceHex, + IN CONST BOOLEAN StopAtSpace + ); + +/** + Function to verify and convert a string to its numerical 64 bit representation. + + If Hex it must be preceeded with a 0x, 0X, or has ForceHex set TRUE. + + @param[in] String The string to evaluate. + @param[out] Value Upon a successful return the value of the conversion. + @param[in] ForceHex TRUE - always assume hex. + @param[in] StopAtSpace TRUE to halt upon finding a space, FALSE to + process the entire String. + + @retval EFI_SUCCESS The conversion was successful. + @retval EFI_INVALID_PARAMETER String contained an invalid character. + @retval EFI_NOT_FOUND String was a number, but Value was NULL. +**/ +EFI_STATUS +EFIAPI +ShellConvertStringToUint64( + IN CONST CHAR16 *String, + OUT UINT64 *Value, + IN CONST BOOLEAN ForceHex, + IN CONST BOOLEAN StopAtSpace + ); + +/** + Function to determine if a given filename exists. + + @param[in] Name Path to test. + + @retval EFI_SUCCESS The Path represents a file. + @retval EFI_NOT_FOUND The Path does not represent a file. + @retval other The path failed to open. +**/ +EFI_STATUS +EFIAPI +ShellFileExists( + IN CONST CHAR16 *Name + ); + +/** + Function to read a single line from a SHELL_FILE_HANDLE. The \n is not included in the returned + buffer. The returned buffer must be callee freed. + + If the position upon start is 0, then the Ascii Boolean will be set. This should be + maintained and not changed for all operations with the same file. + + @param[in] Handle SHELL_FILE_HANDLE to read from. + @param[in, out] Ascii Boolean value for indicating whether the file is + Ascii (TRUE) or UCS2 (FALSE). + + @return The line of text from the file. + + @sa ShellFileHandleReadLine +**/ +CHAR16* +EFIAPI +ShellFileHandleReturnLine( + IN SHELL_FILE_HANDLE Handle, + IN OUT BOOLEAN *Ascii + ); + +/** + Function to read a single line (up to but not including the \n) from a SHELL_FILE_HANDLE. + + If the position upon start is 0, then the Ascii Boolean will be set. This should be + maintained and not changed for all operations with the same file. + + @param[in] Handle SHELL_FILE_HANDLE to read from. + @param[in, out] Buffer The pointer to buffer to read into. + @param[in, out] Size The pointer to number of bytes in Buffer. + @param[in] Truncate If the buffer is large enough, this has no effect. + If the buffer is is too small and Truncate is TRUE, + the line will be truncated. + If the buffer is is too small and Truncate is FALSE, + then no read will occur. + + @param[in, out] Ascii Boolean value for indicating whether the file is + Ascii (TRUE) or UCS2 (FALSE). + + @retval EFI_SUCCESS The operation was successful. The line is stored in + Buffer. + @retval EFI_END_OF_FILE There are no more lines in the file. + @retval EFI_INVALID_PARAMETER Handle was NULL. + @retval EFI_INVALID_PARAMETER Size was NULL. + @retval EFI_BUFFER_TOO_SMALL Size was not large enough to store the line. + Size was updated to the minimum space required. +**/ +EFI_STATUS +EFIAPI +ShellFileHandleReadLine( + IN SHELL_FILE_HANDLE Handle, + IN OUT CHAR16 *Buffer, + IN OUT UINTN *Size, + IN BOOLEAN Truncate, + IN OUT BOOLEAN *Ascii + ); + +/** + Function to delete a file by name + + @param[in] FileName Pointer to file name to delete. + + @retval EFI_SUCCESS the file was deleted sucessfully + @retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not + deleted + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + @retval EFI_NOT_FOUND The specified file could not be found on the + device or the file system could not be found + on the device. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_MEDIA_CHANGED The device has a different medium in it or the + medium is no longer supported. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The file or medium is write protected. + @retval EFI_ACCESS_DENIED The file was opened read only. + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the + file. + @retval other The file failed to open +**/ +EFI_STATUS +EFIAPI +ShellDeleteFileByName( + IN CONST CHAR16 *FileName + ); + +/** + Function to print help file / man page content in the spec from the UEFI Shell protocol GetHelpText function. + + @param[in] CommandToGetHelpOn Pointer to a string containing the command name of help file to be printed. + @param[in] SectionToGetHelpOn Pointer to the section specifier(s). + @param[in] PrintCommandText If TRUE, prints the command followed by the help content, otherwise prints + the help content only. + @retval EFI_DEVICE_ERROR The help data format was incorrect. + @retval EFI_NOT_FOUND The help data could not be found. + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +ShellPrintHelp ( + IN CONST CHAR16 *CommandToGetHelpOn, + IN CONST CHAR16 *SectionToGetHelpOn, + IN BOOLEAN PrintCommandText + ); + +#endif // __SHELL_LIB__ diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Protocol/EfiShellEnvironment2.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Protocol/EfiShellEnvironment2.h new file mode 100644 index 00000000..c6a9a60f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Protocol/EfiShellEnvironment2.h @@ -0,0 +1,969 @@ +/** @file + Defines for EFI shell environment 2 ported to EDK II build environment. (no spec) + + Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef _SHELL_ENVIRONMENT_2_PROTOCOL_H_ +#define _SHELL_ENVIRONMENT_2_PROTOCOL_H_ + +#define DEFAULT_INIT_ROW 1 +#define DEFAULT_AUTO_LF FALSE + +/** + This function is a prototype for a function that dumps information on a protocol + to a given location. The location is dependant on the implementation. This is + used when programatically adding shell commands. + + @param[in] Handle The handle the protocol is on. + @param[in] Interface The interface to the protocol. + +**/ +typedef +VOID +(EFIAPI *SHELLENV_DUMP_PROTOCOL_INFO) ( + IN EFI_HANDLE Handle, + IN VOID *Interface + ); + +/** + This function is a prototype for each command internal to the EFI shell + implementation. The specific command depends on the implementation. This is + used when programatically adding shell commands. + + @param[in] ImageHandle The handle to the binary shell. + @param[in] SystemTable The pointer to the system table. + + @retval EFI_SUCCESS The command completed. + @retval other An error occurred. Any error is possible + depending on the implementation of the shell + command. + +**/ +typedef +EFI_STATUS +(EFIAPI *SHELLENV_INTERNAL_COMMAND) ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + This function is a prototype for one that gets a help string for a given command. + This is used when programatically adding shell commands. Upon successful return + the memory allocated is up to the caller to free. + + @param[in, out] Str Pointer to pointer to string to display for help. + + @retval EFI_SUCCESS The help string is in the parameter Str. + +**/ +typedef +EFI_STATUS +(EFIAPI *SHELLCMD_GET_LINE_HELP) ( + IN OUT CHAR16 **Str + ); + +/** +Structure returned from functions that open multiple files. +**/ +typedef struct { + UINT32 Signature; ///< SHELL_FILE_ARG_SIGNATURE. + LIST_ENTRY Link; ///< Linked list helper. + EFI_STATUS Status; ///< File's status. + + EFI_FILE_HANDLE Parent; ///< What is the Parent file of this file. + UINT64 OpenMode; ///< How was the file opened. + CHAR16 *ParentName; ///< String representation of parent. + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; ///< DevicePath for Parent. + + CHAR16 *FullName; ///< Path and file name for this file. + CHAR16 *FileName; ///< File name for this file. + + EFI_FILE_HANDLE Handle; ///< Handle to this file. + EFI_FILE_INFO *Info; ///< Pointer to file info for this file. +} SHELL_FILE_ARG; + +/// Signature for SHELL_FILE_ARG. +#define SHELL_FILE_ARG_SIGNATURE SIGNATURE_32 ('g', 'r', 'a', 'f') + +/** +GUID for the shell environment2 and shell environment. +**/ +#define SHELL_ENVIRONMENT_PROTOCOL_GUID \ + { \ + 0x47c7b221, 0xc42a, 0x11d2, {0x8e, 0x57, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} \ + } + +/** +GUID for the shell environment2 extension (main GUID above). +**/ +#define EFI_SE_EXT_SIGNATURE_GUID \ + { \ + 0xd2c18636, 0x40e5, 0x4eb5, {0xa3, 0x1b, 0x36, 0x69, 0x5f, 0xd4, 0x2c, 0x87} \ + } + +#define EFI_SHELL_MAJOR_VER 0x00000001 ///< Major version of the EFI_SHELL_ENVIRONMENT2. +#define EFI_SHELL_MINOR_VER 0x00000000 ///< Minor version of the EFI_SHELL_ENVIRONMENT2. + +/** + Execute a command line. + + This function will run the CommandLine. This includes loading any required images, + parsing any requires scripts, and if DebugOutput is TRUE printing errors + encountered directly to the screen. + + @param[in] ParentImageHandle Handle of the image executing this operation. + @param[in] CommandLine The string command line to execute. + @param[in] DebugOutput TRUE indicates that errors should be printed directly. + FALSE suppresses error messages. + + @retval EFI_SUCCESS The command line executed and completed. + @retval EFI_ABORTED The operation aborted. + @retval EFI_INVALID_PARAMETER A parameter did not have a valid value. + @retval EFI_OUT_OF_RESOURCES A required memory allocation failed. + +@sa HandleProtocol +**/ +typedef +EFI_STATUS +(EFIAPI *SHELLENV_EXECUTE) ( + IN EFI_HANDLE *ParentImageHandle, + IN CHAR16 *CommandLine, + IN BOOLEAN DebugOutput + ); + +/** + This function returns a shell environment variable value. + + @param[in] Name The pointer to the string with the shell environment + variable name. + + @retval NULL The shell environment variable's value could not be found. + @retval !=NULL The value of the shell environment variable Name. + +**/ +typedef +CHAR16 * +(EFIAPI *SHELLENV_GET_ENV) ( + IN CHAR16 *Name + ); + +/** + This function returns a shell environment map value. + + @param[in] Name The pointer to the string with the shell environment + map name. + + @retval NULL The shell environment map's value could not be found. + @retval !=NULL The value of the shell environment map Name. + +**/ +typedef +CHAR16 * +(EFIAPI *SHELLENV_GET_MAP) ( + IN CHAR16 *Name + ); + +/** + This function will add an internal command to the shell interface. + + This will allocate all required memory, put the new command on the command + list in the correct location. + + @param[in] Handler The handler function to call when the command gets called. + @param[in] Cmd The command name. + @param[in] GetLineHelp The function to call of type "get help" for this command. + + @retval EFI_SUCCESS The command is now part of the command list. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @sa SHELLENV_INTERNAL_COMMAND + @sa SHELLCMD_GET_LINE_HELP +**/ +typedef +EFI_STATUS +(EFIAPI *SHELLENV_ADD_CMD) ( + IN SHELLENV_INTERNAL_COMMAND Handler, + IN CHAR16 *Cmd, + IN SHELLCMD_GET_LINE_HELP GetLineHelp + ); + +/** + Internal interface to add protocol handlers. + + This function is for internal shell use only. This is how protocol handlers are added. + This will get the current protocol info and add the new info or update existing info + and then resave the info. + + @param[in] Protocol The pointer to the protocol's GUID. + @param[in] DumpToken The function pointer to dump token function or + NULL. + @param[in] DumpInfo The function pointer to dump infomation function + or NULL. + @param[in] IdString The English name of the protocol. +**/ +typedef +VOID +(EFIAPI *SHELLENV_ADD_PROT) ( + IN EFI_GUID *Protocol, + IN SHELLENV_DUMP_PROTOCOL_INFO DumpToken OPTIONAL, + IN SHELLENV_DUMP_PROTOCOL_INFO DumpInfo OPTIONAL, + IN CHAR16 *IdString + ); + +/** + This function finds a protocol handle by a GUID. + + This function will check for already known protocols by GUID and if one is + found it will return the name of that protocol. If no name is found and + GenId is TRUE it will generate ths string. + + @param[in] Protocol The GUID of the protocol to look for. + @param[in] GenId Whether to generate a name string if it is not found. + + @return !NULL The Name of the protocol. + @retval NULL The Name was not found, and GenId was not TRUE. +**/ +typedef +CHAR16* +(EFIAPI *SHELLENV_GET_PROT) ( + IN EFI_GUID *Protocol, + IN BOOLEAN GenId + ); + +/** + This function returns a string array containing the current directory on + a given device. + + If DeviceName is specified, then return the current shell directory on that + device. If DeviceName is NULL, then return the current directory on the + current device. The caller us responsible to free the returned string when + no longer required. + + @param[in] DeviceName The name of the device to get the current + directory on, or NULL for current device. + + @return String array with the current directory on the current or specified device. + +**/ +typedef +CHAR16* +(EFIAPI *SHELLENV_CUR_DIR) ( + IN CHAR16 *DeviceName OPTIONAL + ); + +/** + This function will open a group of files that match the Arg path, including + support for wildcard characters ('?' and '*') in the Arg path. If there are + any wildcard characters in the path this function will find any and all files + that match the wildcards. It returns a double linked list based on the + LIST_ENTRY linked list structure. Use this in conjunction with the + SHELL_FILE_ARG_SIGNATURE to get the SHELL_FILE_ARG structures that are returned. + The memory allocated by the callee for this list is freed by making a call to + SHELLENV_FREE_FILE_LIST. + + @param[in] Arg The pointer Path to files to open. + @param[in, out] ListHead The pointer to the allocated and initialized list head + upon which to append all opened file structures. + + @retval EFI_SUCCESS One or more files was opened and a struct of each file's + information was appended to ListHead. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_NOT_FOUND No matching files could be found. + @sa SHELLENV_FREE_FILE_LIST +**/typedef +EFI_STATUS +(EFIAPI *SHELLENV_FILE_META_ARG) ( + IN CHAR16 *Arg, + IN OUT LIST_ENTRY *ListHead + ); + +/** + This frees all of the nodes under the ListHead, but not ListHead itself. + + @param[in, out] ListHead Pointer to list to free all nodes of. + + @retval EFI_SUCCESS This function always returns EFI_SUCCESS. +**/ +typedef +EFI_STATUS +(EFIAPI *SHELLENV_FREE_FILE_LIST) ( + IN OUT LIST_ENTRY *ListHead + ); + +/** + This function creates a new instance of the ShellInterface protocol for use on + the ImageHandle. + + This function is for internal shell usage. This will allocate and then populate + EFI_SHELL_INTERFACE protocol. It is the caller's responsibility to free the + memory. + + @param[in] ImageHandle The handle which will use the new ShellInterface + protocol. + + @return The newly allocated shell interface protocol. + +**/ +typedef +EFI_SHELL_INTERFACE* +(EFIAPI *SHELLENV_NEW_SHELL) ( + IN EFI_HANDLE ImageHandle + ); + +/** + This function determines whether a script file is currently being processed. + + A script file (.nsh file) can contain a series of commands and this is useful to + know for some shell commands whether they are being run manually or as part of a + script. + + @retval TRUE A script file is being processed. + @retval FALSE A script file is not being processed. +**/ +typedef +BOOLEAN +(EFIAPI *SHELLENV_BATCH_IS_ACTIVE) ( + VOID + ); + +/** + This is an internal shell function to free any and all allocated resources. + This should be called immediately prior to closing the shell. +**/ +typedef +VOID +(EFIAPI *SHELLENV_FREE_RESOURCES) ( + VOID + ); + +/** + This function enables the page break mode. + + This mode causes the output to pause after each complete screen to enable a + user to more easily read it. If AutoWrap is TRUE, then rows with too many + characters will be chopped and divided into 2 rows. If FALSE, then rows with + too many characters may not be fully visible to the user on the screen. + + @param[in] StartRow The row number to start this on. + @param[in] AutoWrap Whether to auto wrap rows that are too long. +**/ +typedef +VOID +(EFIAPI *SHELLENV_ENABLE_PAGE_BREAK) ( + IN INT32 StartRow, + IN BOOLEAN AutoWrap + ); + +/** + This function disables the page break mode. + + Disabling this causes the output to print out exactly as coded, with no breaks + for readability. +**/ +typedef +VOID +(EFIAPI *SHELLENV_DISABLE_PAGE_BREAK) ( + VOID + ); + +/** + Get the status of the page break output mode. + + @retval FALSE Page break output mode is not enabled. + @retval TRUE Page break output mode is enabled. +**/ +typedef +BOOLEAN +(EFIAPI *SHELLENV_GET_PAGE_BREAK) ( + VOID + ); + +/** + This function sets the keys to filter for for the console in. The valid + values to set are: + + #define EFI_OUTPUT_SCROLL 0x00000001 + #define EFI_OUTPUT_PAUSE 0x00000002 + #define EFI_EXECUTION_BREAK 0x00000004 + + @param[in] KeyFilter The new key filter to use. +**/ +typedef +VOID +(EFIAPI *SHELLENV_SET_KEY_FILTER) ( + IN UINT32 KeyFilter + ); + +/** + This function gets the keys to filter for for the console in. + + The valid values to get are: + #define EFI_OUTPUT_SCROLL 0x00000001 + #define EFI_OUTPUT_PAUSE 0x00000002 + #define EFI_EXECUTION_BREAK 0x00000004 + + @retval The current filter mask. +**/ +typedef +UINT32 +(EFIAPI *SHELLENV_GET_KEY_FILTER) ( + VOID + ); + +/** + This function determines if the shell application should break. + + This is used to inform a shell application that a break condition has been + initiated. Long loops should check this to prevent delays to the break. + + @retval TRUE A break has been signaled. The application + should exit with EFI_ABORTED as soon as possible. + @retval FALSE Continue as normal. +**/ +typedef +BOOLEAN +(EFIAPI *SHELLENV_GET_EXECUTION_BREAK) ( + VOID + ); + +/** + This is an internal shell function used to increment the shell nesting level. + +**/ +typedef +VOID +(EFIAPI *SHELLENV_INCREMENT_SHELL_NESTING_LEVEL) ( + VOID + ); + +/** + This is an internal shell function used to decrement the shell nesting level. +**/ +typedef +VOID +(EFIAPI *SHELLENV_DECREMENT_SHELL_NESTING_LEVEL) ( + VOID + ); + +/** + This function determines if the caller is running under the root shell. + + @retval TRUE The caller is running under the root shell. + @retval FALSE The caller is not running under the root shell. + +**/ +typedef +BOOLEAN +(EFIAPI *SHELLENV_IS_ROOT_SHELL) ( + VOID + ); + +/** + Close the console proxy to restore the original console. + + This is an internal shell function to handle shell cascading. It restores the + original set of console protocols. + + @param[in] ConInHandle The handle of ConIn. + @param[in, out] ConIn The pointer to the location to return the pointer to + the original console input. + @param[in] ConOutHandle The handle of ConOut + @param[in, out] ConOut The pointer to the location to return the pointer to + the original console output. +**/ +typedef +VOID +(EFIAPI *SHELLENV_CLOSE_CONSOLE_PROXY) ( + IN EFI_HANDLE ConInHandle, + IN OUT EFI_SIMPLE_TEXT_INPUT_PROTOCOL **ConIn, + IN EFI_HANDLE ConOutHandle, + IN OUT EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL **ConOut + ); + +// +// declarations of handle enumerator +// +/** + For ease of use the shell maps handle #'s to short numbers. + This is only done on request for various internal commands and the references + are immediately freed when the internal command completes. +**/ +typedef +VOID +(EFIAPI *INIT_HANDLE_ENUMERATOR) ( + VOID + ); + +/** + This is an internal shell function to enumerate the handle database. + + This function gets the next handle in the handle database. If no handles are + found, EFI_NOT_FOUND is returned. If the previous Handle was the last handle, + it is set to NULL before returning. + + This must be called after INIT_HANDLE_ENUMERATOR and before CLOSE_HANDLE_ENUMERATOR. + + @param[in, out] Handle The pointer to pointer to Handle. It is set + on a sucessful return. + + @retval EFI_SUCCESS The next handle in the handle database is *Handle. + @retval EFI_NOT_FOUND There is not another handle. +**/ +typedef +EFI_STATUS +(EFIAPI *NEXT_HANDLE) ( + IN OUT EFI_HANDLE **Handle + ); + +/** + This is an internal shell function to enumerate the handle database. + + This function skips the next SkipNum handles in the handle database. If there + are not enough handles left to skip that many EFI_ACCESS_DENIED is returned and + no skip is performed. + + This must be called after INIT_HANDLE_ENUMERATOR and before CLOSE_HANDLE_ENUMERATOR. + + @param[in] SkipNum How many handles to skip + + @retval EFI_SUCCESS The next handle in the handle database is *Handle + @retval EFI_ACCESS_DENIED There are not SkipNum handles left in the database +**/ +typedef +EFI_STATUS +(EFIAPI *SKIP_HANDLE) ( + IN UINTN SkipNum + ); + +/** + This is an internal shell function to enumerate the handle database. + + This function resets the the handle database so that NEXT_HANDLE and SKIP_HANDLE + will start from EnumIndex on the next call. + + This must be called after INIT_HANDLE_ENUMERATOR and before CLOSE_HANDLE_ENUMERATOR. + + @param[in] EnumIndex Where to start. + + @return The number of handles either read out or skipped before this reset. +**/ +typedef +UINTN +(EFIAPI *RESET_HANDLE_ENUMERATOR) ( + IN UINTN EnumIndex + ); + +/** + This is an internal shell function to enumerate the handle database. + + This must be called after INIT_HANDLE_ENUMERATOR. + + This function releases all memory and resources associated with the handle database. + After this no other handle enumerator functions except INIT_HANDLE_ENUMERATOR will + function properly. +**/ +typedef +VOID +(EFIAPI *CLOSE_HANDLE_ENUMERATOR) ( + VOID + ); + +/** + This is an internal shell function to enumerate the handle database. + + This function returns the number of handles in the handle database. + + This must be called after INIT_HANDLE_ENUMERATOR and before CLOSE_HANDLE_ENUMERATOR. + + @return The number of handles in the handle database. +**/ +typedef +UINTN +(EFIAPI *GET_NUM) ( + VOID + ); + +/** +Handle Enumerator structure. +**/ +typedef struct { + INIT_HANDLE_ENUMERATOR Init; ///< The pointer to INIT_HANDLE_ENUMERATOR function. + NEXT_HANDLE Next; ///< The pointer to NEXT_HANDLE function. + SKIP_HANDLE Skip; ///< The pointer to SKIP_HANDLE function. + RESET_HANDLE_ENUMERATOR Reset; ///< The pointer to RESET_HANDLE_ENUMERATOR function. + CLOSE_HANDLE_ENUMERATOR Close; ///< The pointer to CLOSE_HANDLE_ENUMERATOR function. + GET_NUM GetNum; ///< The pointer to GET_NUM function. +} HANDLE_ENUMERATOR; + +/** + Signature for the PROTOCOL_INFO structure. +**/ +#define PROTOCOL_INFO_SIGNATURE SIGNATURE_32 ('s', 'p', 'i', 'n') + +/** + PROTOCOL_INFO structure for protocol enumerator functions. +**/ +typedef struct { + UINTN Signature; ///< PROTOCOL_INFO_SIGNATURE. + LIST_ENTRY Link; ///< Standard linked list helper member. + // + // The parsing info for the protocol. + // + EFI_GUID ProtocolId; ///< The GUID for the protocol. + CHAR16 *IdString; ///< The name of the protocol. + SHELLENV_DUMP_PROTOCOL_INFO DumpToken; ///< The pointer to DumpToken function for the protocol. + SHELLENV_DUMP_PROTOCOL_INFO DumpInfo; ///< The pointer to DumpInfo function for the protocol. + // + // Patabase info on which handles are supporting this protocol. + // + UINTN NoHandles; ///< The number of handles producing this protocol. + EFI_HANDLE *Handles; ///< The array of handles. + +} PROTOCOL_INFO; + +// +// Declarations of protocol info enumerator. +// +/** + This is an internal shell function to initialize the protocol enumerator. + + This must be called before NEXT_PROTOCOL_INFO, SKIP_PROTOCOL_INFO, + RESET_PROTOCOL_INFO_ENUMERATOR, and CLOSE_PROTOCOL_INFO_ENUMERATOR are + called. +**/ +typedef +VOID +(EFIAPI *INIT_PROTOCOL_INFO_ENUMERATOR) ( + VOID + ); + +/** + This function is an internal shell function for enumeration of protocols. + + This function returns the next protocol on the list. If this is called + immediately after initialization, it will return the first protocol on the list. + If this is called immediately after reset, it will return the first protocol again. + + This cannot be called after CLOSE_PROTOCOL_INFO_ENUMERATOR, but it must be + called after INIT_PROTOCOL_INFO_ENUMERATOR. + + @param[in, out] ProtocolInfo The pointer to pointer to protocol information structure. + + @retval EFI_SUCCESS The next protocol's information was sucessfully returned. + @retval NULL There are no more protocols. +**/ +typedef +EFI_STATUS +(EFIAPI *NEXT_PROTOCOL_INFO) ( + IN OUT PROTOCOL_INFO **ProtocolInfo + ); + +/** + This function is an internal shell function for enumeration of protocols. + + This cannot be called after CLOSE_PROTOCOL_INFO_ENUMERATOR, but it must be + called after INIT_PROTOCOL_INFO_ENUMERATOR. + + This function does nothing and always returns EFI_SUCCESS. + + @retval EFI_SUCCESS Always returned (see above). +**/ +typedef +EFI_STATUS +(EFIAPI *SKIP_PROTOCOL_INFO) ( + IN UINTN SkipNum + ); + +/** + This function is an internal shell function for enumeration of protocols. + + This cannot be called after CLOSE_PROTOCOL_INFO_ENUMERATOR, but it must be + called after INIT_PROTOCOL_INFO_ENUMERATOR. + + This function resets the list of protocols such that the next one in the + list is the begining of the list. +**/ +typedef +VOID +(EFIAPI *RESET_PROTOCOL_INFO_ENUMERATOR) ( + VOID + ); + + +/** + This function is an internal shell function for enumeration of protocols. + + This must be called after INIT_PROTOCOL_INFO_ENUMERATOR. After this call + no protocol enumerator calls except INIT_PROTOCOL_INFO_ENUMERATOR may be made. + + This function frees any memory or resources associated with the protocol + enumerator. +**/ +typedef +VOID +(EFIAPI *CLOSE_PROTOCOL_INFO_ENUMERATOR) ( + VOID + ); + +/** + Protocol enumerator structure of function pointers. +**/ +typedef struct { + INIT_PROTOCOL_INFO_ENUMERATOR Init; ///< The pointer to INIT_PROTOCOL_INFO_ENUMERATOR function. + NEXT_PROTOCOL_INFO Next; ///< The pointer to NEXT_PROTOCOL_INFO function. + SKIP_PROTOCOL_INFO Skip; ///< The pointer to SKIP_PROTOCOL_INFO function. + RESET_PROTOCOL_INFO_ENUMERATOR Reset; ///< The pointer to RESET_PROTOCOL_INFO_ENUMERATOR function. + CLOSE_PROTOCOL_INFO_ENUMERATOR Close; ///< The pointer to CLOSE_PROTOCOL_INFO_ENUMERATOR function. +} PROTOCOL_INFO_ENUMERATOR; + +/** + This function is used to retrieve a user-friendly display name for a handle. + + If UseComponentName is TRUE then the component name protocol for this device + or it's parent device (if required) will be used to obtain the name of the + device. If UseDevicePath is TRUE it will get the human readable device path + and return that. If both are TRUE it will try to use component name first + and device path if that fails. + + It will use either ComponentName or ComponentName2 protocol, depending on + what is present. + + This function will furthur verify whether the handle in question produced either + EFI_DRIVER_CONFIGRATION_PROTOCOL or EFI_DRIVER_CONFIGURATION2_PROTOCOL and also + whether the handle in question produced either EFI_DRIVER_DIAGNOSTICS_PROTOCOL or + EFI_DRIVER_DIAGNOSTICS2_PROTOCOL. + + Upon successful return, the memory for *BestDeviceName is up to the caller to free. + + @param[in] DeviceHandle The device handle whose name is desired. + @param[in] UseComponentName Whether to use the ComponentName protocol at all. + @param[in] UseDevicePath Whether to use the DevicePath protocol at all. + @param[in] Language The pointer to the language string to use. + @param[in, out] BestDeviceName The pointer to pointer to string allocated with the name. + @param[out] ConfigurationStatus The pointer to status for opening a Configuration protocol. + @param[out] DiagnosticsStatus The pointer to status for opening a Diagnostics protocol. + @param[in] Display Whether to Print this out to default Print location. + @param[in] Indent How many characters to indent the printing. + + @retval EFI_SUCCESS This function always returns EFI_SUCCESS. +**/ +typedef +EFI_STATUS +(EFIAPI *GET_DEVICE_NAME) ( + IN EFI_HANDLE DeviceHandle, + IN BOOLEAN UseComponentName, + IN BOOLEAN UseDevicePath, + IN CHAR8 *Language, + IN OUT CHAR16 **BestDeviceName, + OUT EFI_STATUS *ConfigurationStatus, + OUT EFI_STATUS *DiagnosticsStatus, + IN BOOLEAN Display, + IN UINTN Indent + ); + +#define EFI_SHELL_COMPATIBLE_MODE_VER L"1.1.1" ///< The string for lowest version this shell supports. +#define EFI_SHELL_ENHANCED_MODE_VER L"1.1.2" ///< The string for highest version this shell supports. + +/** + This function gets the shell mode as stored in the shell environment + "efishellmode". It will not fail. + + @param[out] Mode Returns a string representing one of the + 2 supported modes of the shell. + + @retval EFI_SUCCESS This function always returns success. +**/ +typedef +EFI_STATUS +(EFIAPI *GET_SHELL_MODE) ( + OUT CHAR16 **Mode + ); + +/** + Convert a file system style name to a device path. + + This function will convert a shell path name to a Device Path Protocol path. + This function will allocate any required memory for this operation and it + is the responsibility of the caller to free that memory when no longer required. + + If anything prevents the complete conversion free any allocated memory and + return NULL. + + @param[in] Path The path to convert. + + @retval !NULL A pointer to the callee allocated Device Path. + @retval NULL The operation could not be completed. +**/ +typedef +EFI_DEVICE_PATH_PROTOCOL* +(EFIAPI *SHELLENV_NAME_TO_PATH) ( + IN CHAR16 *Path + ); + +/** + Converts a device path into a file system map name. + + If DevPath is NULL, then ASSERT. + + This function looks through the shell environment map for a map whose device + path matches the DevPath parameter. If one is found the Name is returned via + Name parameter. If sucessful the caller must free the memory allocated for + Name. + + This function will use the internal lock to prevent changes to the map during + the lookup operation. + + @param[in] DevPath The device path to search for a name for. + @param[in] ConsistMapping What state to verify map flag VAR_ID_CONSIST. + @param[out] Name On sucessful return the name of that device path. + + @retval EFI_SUCCESS The DevPath was found and the name returned + in Name. + @retval EFI_OUT_OF_RESOURCES A required memory allocation failed. + @retval EFI_UNSUPPORTED The DevPath was not found in the map. +**/ +typedef +EFI_STATUS +(EFIAPI *SHELLENV_GET_FS_NAME) ( + IN EFI_DEVICE_PATH_PROTOCOL * DevPath, + IN BOOLEAN ConsistMapping, + OUT CHAR16 **Name + ); + +/** + This function will open a group of files that match the Arg path, but will not + support the wildcard characters ('?' and '*') in the Arg path. If there are + any wildcard characters in the path this function will return + EFI_INVALID_PARAMETER. The return is a double linked list based on the + LIST_ENTRY linked list structure. Use this in conjunction with the + SHELL_FILE_ARG_SIGNATURE to get the SHELL_FILE_ARG structures that are returned. + The memory allocated by the callee for this list is freed by making a call to + SHELLENV_FREE_FILE_LIST. + + @param[in] Arg The pointer to the path of the files to be opened. + @param[in, out] ListHead The pointer to allocated and initialized list head + upon which to append all the opened file structures. + + @retval EFI_SUCCESS One or more files was opened and a struct of each file's + information was appended to ListHead. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_NOT_FOUND No matching files could be found. + @sa SHELLENV_FREE_FILE_LIST +**/ +typedef +EFI_STATUS +(EFIAPI *SHELLENV_FILE_META_ARG_NO_WILDCARD) ( + IN CHAR16 *Arg, + IN OUT LIST_ENTRY *ListHead + ); + +/** + This function removes duplicate file listings from lists. + + This is a function for use with SHELLENV_FILE_META_ARG_NO_WILDCARD and + SHELLENV_FILE_META_ARG. This function will verify that there are no duplicate + files in the list of returned files. Any file listed twice will have one of its + instances removed. + + @param[in] ListHead The pointer to linked list head that was returned from + SHELLENV_FILE_META_ARG_NO_WILDCARD or + SHELLENV_FILE_META_ARG. + + @retval EFI_SUCCESS This function always returns success. + +**/ +typedef +EFI_STATUS +(EFIAPI *SHELLENV_DEL_DUP_FILE) ( + IN LIST_ENTRY * ListHead + ); + +/** + Converts a File System map name to a device path. + + If DevPath is NULL, then ASSERT(). + + This function looks through the shell environment map for a map whose Name + matches the Name parameter. If one is found, the device path pointer is + updated to point to that file systems device path. The caller should not + free the memory from that device path. + + This function will use the internal lock to prevent changes to the map during + the lookup operation. + + @param[in] Name The pointer to the NULL terminated UNICODE string of the + file system name. + @param[out] DevPath The pointer to pointer to DevicePath. Only valid on + successful return. + + @retval EFI_SUCCESS The conversion was successful, and the device + path was returned. + @retval EFI_NOT_FOUND The file system could not be found in the map. +**/ +typedef +EFI_STATUS +(EFIAPI *SHELLENV_GET_FS_DEVICE_PATH) ( + IN CHAR16 *Name, + OUT EFI_DEVICE_PATH_PROTOCOL **DevPath + ); + +/// EFI_SHELL_ENVIRONMENT2 protocol structure. +typedef struct { + SHELLENV_EXECUTE Execute; + SHELLENV_GET_ENV GetEnv; + SHELLENV_GET_MAP GetMap; + SHELLENV_ADD_CMD AddCmd; + SHELLENV_ADD_PROT AddProt; + SHELLENV_GET_PROT GetProt; + SHELLENV_CUR_DIR CurDir; + SHELLENV_FILE_META_ARG FileMetaArg; + SHELLENV_FREE_FILE_LIST FreeFileList; + + // + // The following services are only used by the shell itself. + // + SHELLENV_NEW_SHELL NewShell; + SHELLENV_BATCH_IS_ACTIVE BatchIsActive; + + SHELLENV_FREE_RESOURCES FreeResources; + + // + // GUID to differentiate ShellEnvironment2 from ShellEnvironment. + // + EFI_GUID SESGuid; + // + // Major Version grows if shell environment interface has been changes. + // + UINT32 MajorVersion; + UINT32 MinorVersion; + SHELLENV_ENABLE_PAGE_BREAK EnablePageBreak; + SHELLENV_DISABLE_PAGE_BREAK DisablePageBreak; + SHELLENV_GET_PAGE_BREAK GetPageBreak; + + SHELLENV_SET_KEY_FILTER SetKeyFilter; + SHELLENV_GET_KEY_FILTER GetKeyFilter; + + SHELLENV_GET_EXECUTION_BREAK GetExecutionBreak; + SHELLENV_INCREMENT_SHELL_NESTING_LEVEL IncrementShellNestingLevel; + SHELLENV_DECREMENT_SHELL_NESTING_LEVEL DecrementShellNestingLevel; + SHELLENV_IS_ROOT_SHELL IsRootShell; + + SHELLENV_CLOSE_CONSOLE_PROXY CloseConsoleProxy; + HANDLE_ENUMERATOR HandleEnumerator; + PROTOCOL_INFO_ENUMERATOR ProtocolInfoEnumerator; + GET_DEVICE_NAME GetDeviceName; + GET_SHELL_MODE GetShellMode; + SHELLENV_NAME_TO_PATH NameToPath; + SHELLENV_GET_FS_NAME GetFsName; + SHELLENV_FILE_META_ARG_NO_WILDCARD FileMetaArgNoWildCard; + SHELLENV_DEL_DUP_FILE DelDupFileArg; + SHELLENV_GET_FS_DEVICE_PATH GetFsDevicePath; +} EFI_SHELL_ENVIRONMENT2; + +extern EFI_GUID gEfiShellEnvironment2Guid; +extern EFI_GUID gEfiShellEnvironment2ExtGuid; + +#endif // _SHELL_ENVIRONMENT_2_PROTOCOL_H_ diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Protocol/EfiShellInterface.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Protocol/EfiShellInterface.h new file mode 100644 index 00000000..7a1f2fa1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Include/Protocol/EfiShellInterface.h @@ -0,0 +1,88 @@ +/** @file + EFI Shell Interface protocol from EDK shell (no spec). + + Shell Interface - additional information (over image_info) provided + to an application started by the shell. + + ConIo provides a file-style interface to the console. + + The shell interface's and data (including ConIo) are only valid during + the applications Entry Point. Once the application returns from it's + entry point the data is freed by the invoking shell. + + Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SHELLINTERFACE_H_ +#define _SHELLINTERFACE_H_ + +#include + +#define SHELL_INTERFACE_PROTOCOL_GUID \ + { \ + 0x47c7b223, 0xc42a, 0x11d2, {0x8e, 0x57, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} \ + } + +/// +/// Bit definitions for EFI_SHELL_ARG_INFO +/// +typedef enum { + ARG_NO_ATTRIB = 0x0, + ARG_IS_QUOTED = BIT0, + ARG_PARTIALLY_QUOTED = BIT1, + ARG_FIRST_HALF_QUOTED = BIT2, + ARG_FIRST_CHAR_IS_ESC = BIT3 +} EFI_SHELL_ARG_INFO_TYPES; + +/// +/// Attributes for an argument. +/// +typedef struct _EFI_SHELL_ARG_INFO { + UINT32 Attributes; +} EFI_SHELL_ARG_INFO; + +/// +/// This protocol provides access to additional information about a shell application. +/// +typedef struct { + /// + /// Handle back to original image handle & image information. + /// + EFI_HANDLE ImageHandle; + EFI_LOADED_IMAGE_PROTOCOL *Info; + + /// + /// Parsed arg list converted more C-like format. + /// + CHAR16 **Argv; + UINTN Argc; + + /// + /// Storage for file redirection args after parsing. + /// + CHAR16 **RedirArgv; + UINTN RedirArgc; + + /// + /// A file style handle for console io. + /// + EFI_FILE_PROTOCOL *StdIn; + EFI_FILE_PROTOCOL *StdOut; + EFI_FILE_PROTOCOL *StdErr; + + /// + /// List of attributes for each argument. + /// + EFI_SHELL_ARG_INFO *ArgInfo; + + /// + /// Whether we are echoing. + /// + BOOLEAN EchoOn; +} EFI_SHELL_INTERFACE; + +extern EFI_GUID gEfiShellInterfaceGuid; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c new file mode 100644 index 00000000..23930954 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c @@ -0,0 +1,3732 @@ +/** @file + Provides interface to advanced shell functionality for parsing both handle and protocol database. + + Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.
+ (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
+ (C) Copyright 2015-2021 Hewlett Packard Enterprise Development LP
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiHandleParsingLib.h" +#include "IndustryStandard/Acpi10.h" +#include "IndustryStandard/Pci.h" +#include +#include + +EFI_HII_HANDLE mHandleParsingHiiHandle = NULL; +HANDLE_INDEX_LIST mHandleList = {{{NULL,NULL},0,0},0}; +GUID_INFO_BLOCK *mGuidList; +UINTN mGuidListCount; + +/** + Function to find the file name associated with a LoadedImageProtocol. + + @param[in] LoadedImage An instance of LoadedImageProtocol. + + @retval A string representation of the file name associated + with LoadedImage, or NULL if no name can be found. +**/ +CHAR16* +FindLoadedImageFileName ( + IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage + ) +{ + EFI_GUID *NameGuid; + EFI_STATUS Status; + EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; + VOID *Buffer; + UINTN BufferSize; + UINT32 AuthenticationStatus; + + if ((LoadedImage == NULL) || (LoadedImage->FilePath == NULL)) { + return NULL; + } + + NameGuid = EfiGetNameGuidFromFwVolDevicePathNode((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)LoadedImage->FilePath); + + if (NameGuid == NULL) { + return NULL; + } + + // + // Get the FirmwareVolume2Protocol of the device handle that this image was loaded from. + // + Status = gBS->HandleProtocol (LoadedImage->DeviceHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID**) &Fv); + + // + // FirmwareVolume2Protocol is PI, and is not required to be available. + // + if (EFI_ERROR (Status)) { + return NULL; + } + + // + // Read the user interface section of the image. + // + Buffer = NULL; + Status = Fv->ReadSection(Fv, NameGuid, EFI_SECTION_USER_INTERFACE, 0, &Buffer, &BufferSize, &AuthenticationStatus); + + if (EFI_ERROR (Status)) { + return NULL; + } + + // + // ReadSection returns just the section data, without any section header. For + // a user interface section, the only data is the file name. + // + return Buffer; +} + +/** + Function to translate the EFI_MEMORY_TYPE into a string. + + @param[in] Memory The memory type. + + @retval A string representation of the type allocated from BS Pool. +**/ +CHAR16* +ConvertMemoryType ( + IN CONST EFI_MEMORY_TYPE Memory + ) +{ + CHAR16 *RetVal; + RetVal = NULL; + + switch (Memory) { + case EfiReservedMemoryType: StrnCatGrow(&RetVal, NULL, L"EfiReservedMemoryType", 0); break; + case EfiLoaderCode: StrnCatGrow(&RetVal, NULL, L"EfiLoaderCode", 0); break; + case EfiLoaderData: StrnCatGrow(&RetVal, NULL, L"EfiLoaderData", 0); break; + case EfiBootServicesCode: StrnCatGrow(&RetVal, NULL, L"EfiBootServicesCode", 0); break; + case EfiBootServicesData: StrnCatGrow(&RetVal, NULL, L"EfiBootServicesData", 0); break; + case EfiRuntimeServicesCode: StrnCatGrow(&RetVal, NULL, L"EfiRuntimeServicesCode", 0); break; + case EfiRuntimeServicesData: StrnCatGrow(&RetVal, NULL, L"EfiRuntimeServicesData", 0); break; + case EfiConventionalMemory: StrnCatGrow(&RetVal, NULL, L"EfiConventionalMemory", 0); break; + case EfiUnusableMemory: StrnCatGrow(&RetVal, NULL, L"EfiUnusableMemory", 0); break; + case EfiACPIReclaimMemory: StrnCatGrow(&RetVal, NULL, L"EfiACPIReclaimMemory", 0); break; + case EfiACPIMemoryNVS: StrnCatGrow(&RetVal, NULL, L"EfiACPIMemoryNVS", 0); break; + case EfiMemoryMappedIO: StrnCatGrow(&RetVal, NULL, L"EfiMemoryMappedIO", 0); break; + case EfiMemoryMappedIOPortSpace: StrnCatGrow(&RetVal, NULL, L"EfiMemoryMappedIOPortSpace", 0); break; + case EfiPalCode: StrnCatGrow(&RetVal, NULL, L"EfiPalCode", 0); break; + case EfiMaxMemoryType: StrnCatGrow(&RetVal, NULL, L"EfiMaxMemoryType", 0); break; + default: ASSERT(FALSE); + } + return (RetVal); +} + +/** + Function to translate the EFI_GRAPHICS_PIXEL_FORMAT into a string. + + @param[in] Fmt The format type. + + @retval A string representation of the type allocated from BS Pool. +**/ +CHAR16* +ConvertPixelFormat ( + IN CONST EFI_GRAPHICS_PIXEL_FORMAT Fmt + ) +{ + CHAR16 *RetVal; + RetVal = NULL; + + switch (Fmt) { + case PixelRedGreenBlueReserved8BitPerColor: StrnCatGrow(&RetVal, NULL, L"PixelRedGreenBlueReserved8BitPerColor", 0); break; + case PixelBlueGreenRedReserved8BitPerColor: StrnCatGrow(&RetVal, NULL, L"PixelBlueGreenRedReserved8BitPerColor", 0); break; + case PixelBitMask: StrnCatGrow(&RetVal, NULL, L"PixelBitMask", 0); break; + case PixelBltOnly: StrnCatGrow(&RetVal, NULL, L"PixelBltOnly", 0); break; + case PixelFormatMax: StrnCatGrow(&RetVal, NULL, L"PixelFormatMax", 0); break; + default: ASSERT(FALSE); + } + return (RetVal); +} + +/** + Constructor for the library. + + @param[in] ImageHandle Ignored. + @param[in] SystemTable Ignored. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +HandleParsingLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + mGuidListCount = 0; + mGuidList = NULL; + + // + // Do nothing with mHandleParsingHiiHandle. Initialize HII as needed. + // + return (EFI_SUCCESS); +} + +/** + Initialization function for HII packages. + +**/ +VOID +HandleParsingHiiInit (VOID) +{ + if (mHandleParsingHiiHandle == NULL) { + mHandleParsingHiiHandle = HiiAddPackages (&gHandleParsingHiiGuid, gImageHandle, UefiHandleParsingLibStrings, NULL); + ASSERT (mHandleParsingHiiHandle != NULL); + } +} + +/** + Destructor for the library. free any resources. + + @param[in] ImageHandle Ignored. + @param[in] SystemTable Ignored. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +HandleParsingLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + UINTN LoopCount; + + for (LoopCount = 0; mGuidList != NULL && LoopCount < mGuidListCount; LoopCount++) { + SHELL_FREE_NON_NULL(mGuidList[LoopCount].GuidId); + } + + SHELL_FREE_NON_NULL(mGuidList); + if (mHandleParsingHiiHandle != NULL) { + HiiRemovePackages(mHandleParsingHiiHandle); + } + return (EFI_SUCCESS); +} + +/** + Function to dump information about LoadedImage. + + This will allocate the return buffer from boot services pool. + + @param[in] TheHandle The handle that has LoadedImage installed. + @param[in] Verbose TRUE for additional information, FALSE otherwise. + + @retval A poitner to a string containing the information. +**/ +CHAR16* +EFIAPI +LoadedImageProtocolDumpInformation( + IN CONST EFI_HANDLE TheHandle, + IN CONST BOOLEAN Verbose + ) +{ + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + EFI_STATUS Status; + CHAR16 *RetVal; + CHAR16 *Temp; + CHAR16 *FileName; + CHAR8 *PdbFileName; + CHAR16 *FilePath; + CHAR16 *CodeType; + CHAR16 *DataType; + + Status = gBS->OpenProtocol ( + TheHandle, + &gEfiLoadedImageProtocolGuid, + (VOID**)&LoadedImage, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return NULL; + } + + FileName = FindLoadedImageFileName(LoadedImage); + FilePath = ConvertDevicePathToText(LoadedImage->FilePath, TRUE, TRUE); + if (!Verbose) { + if (FileName == NULL) { + FileName = FilePath; + } else { + SHELL_FREE_NON_NULL(FilePath); + } + return FileName; + } + + HandleParsingHiiInit(); + RetVal = NULL; + if (FileName != NULL) { + Temp = HiiGetString(mHandleParsingHiiHandle, STRING_TOKEN(STR_LI_DUMP_NAME), NULL); + + if (Temp != NULL) { + RetVal = CatSPrint(NULL, Temp, FileName); + } + + SHELL_FREE_NON_NULL(Temp); + SHELL_FREE_NON_NULL(FileName); + } + + Temp = HiiGetString(mHandleParsingHiiHandle, STRING_TOKEN(STR_LI_DUMP_MAIN), NULL); + if (Temp == NULL) { + return NULL; + } + PdbFileName = PeCoffLoaderGetPdbPointer (LoadedImage->ImageBase); + DataType = ConvertMemoryType(LoadedImage->ImageDataType); + CodeType = ConvertMemoryType(LoadedImage->ImageCodeType); + + RetVal = CatSPrint( + RetVal, + Temp, + LoadedImage->Revision, + LoadedImage->ParentHandle, + LoadedImage->SystemTable, + LoadedImage->DeviceHandle, + FilePath, + PdbFileName, + LoadedImage->LoadOptionsSize, + LoadedImage->LoadOptions, + LoadedImage->ImageBase, + LoadedImage->ImageSize, + CodeType, + DataType, + LoadedImage->Unload + ); + + + SHELL_FREE_NON_NULL(Temp); + SHELL_FREE_NON_NULL(FilePath); + SHELL_FREE_NON_NULL(CodeType); + SHELL_FREE_NON_NULL(DataType); + + return RetVal; +} + +/** + Function to dump information about GOP. + + This will allocate the return buffer from boot services pool. + + @param[in] TheHandle The handle that has LoadedImage installed. + @param[in] Verbose TRUE for additional information, FALSE otherwise. + + @retval A poitner to a string containing the information. +**/ +CHAR16* +EFIAPI +GraphicsOutputProtocolDumpInformation( + IN CONST EFI_HANDLE TheHandle, + IN CONST BOOLEAN Verbose + ) +{ + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; + EFI_STATUS Status; + CHAR16 *RetVal; + CHAR16 *Temp; + CHAR16 *Fmt; + CHAR16 *TempRetVal; + UINTN GopInfoSize; + UINT32 Mode; + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *GopInfo; + + if (!Verbose) { + return (CatSPrint(NULL, L"GraphicsOutput")); + } + + HandleParsingHiiInit(); + + Temp = HiiGetString(mHandleParsingHiiHandle, STRING_TOKEN(STR_GOP_DUMP_MAIN), NULL); + if (Temp == NULL) { + return NULL; + } + + Status = gBS->OpenProtocol ( + TheHandle, + &gEfiGraphicsOutputProtocolGuid, + (VOID**)&GraphicsOutput, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + SHELL_FREE_NON_NULL (Temp); + return NULL; + } + + Fmt = ConvertPixelFormat(GraphicsOutput->Mode->Info->PixelFormat); + + RetVal = CatSPrint( + NULL, + Temp, + GraphicsOutput->Mode->MaxMode, + GraphicsOutput->Mode->Mode, + GraphicsOutput->Mode->FrameBufferBase, + (UINT64)GraphicsOutput->Mode->FrameBufferSize, + (UINT64)GraphicsOutput->Mode->SizeOfInfo, + GraphicsOutput->Mode->Info->Version, + GraphicsOutput->Mode->Info->HorizontalResolution, + GraphicsOutput->Mode->Info->VerticalResolution, + Fmt, + GraphicsOutput->Mode->Info->PixelsPerScanLine, + GraphicsOutput->Mode->Info->PixelFormat!=PixelBitMask?0:GraphicsOutput->Mode->Info->PixelInformation.RedMask, + GraphicsOutput->Mode->Info->PixelFormat!=PixelBitMask?0:GraphicsOutput->Mode->Info->PixelInformation.GreenMask, + GraphicsOutput->Mode->Info->PixelFormat!=PixelBitMask?0:GraphicsOutput->Mode->Info->PixelInformation.BlueMask + ); + + SHELL_FREE_NON_NULL (Temp); + + Temp = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN (STR_GOP_RES_LIST_MAIN), NULL); + if (Temp == NULL) { + SHELL_FREE_NON_NULL (RetVal); + goto EXIT; + } + + TempRetVal = CatSPrint (RetVal, Temp); + SHELL_FREE_NON_NULL (RetVal); + if (TempRetVal == NULL) { + goto EXIT; + } + RetVal = TempRetVal; + SHELL_FREE_NON_NULL (Temp); + + Temp = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN (STR_GOP_RES_LIST_ENTRY), NULL); + if (Temp == NULL) { + SHELL_FREE_NON_NULL (RetVal); + goto EXIT; + } + + + for (Mode = 0; Mode < GraphicsOutput->Mode->MaxMode; Mode++) { + Status = GraphicsOutput->QueryMode ( + GraphicsOutput, + Mode, + &GopInfoSize, + &GopInfo + ); + if (EFI_ERROR (Status)) { + continue; + } + + TempRetVal = CatSPrint ( + RetVal, + Temp, + Mode, + GopInfo->HorizontalResolution, + GopInfo->VerticalResolution + ); + + SHELL_FREE_NON_NULL (GopInfo); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + } + + +EXIT: + SHELL_FREE_NON_NULL(Temp); + SHELL_FREE_NON_NULL(Fmt); + + return RetVal; +} + +/** + Function to dump information about EDID Discovered Protocol. + + This will allocate the return buffer from boot services pool. + + @param[in] TheHandle The handle that has LoadedImage installed. + @param[in] Verbose TRUE for additional information, FALSE otherwise. + + @retval A pointer to a string containing the information. +**/ +CHAR16* +EFIAPI +EdidDiscoveredProtocolDumpInformation ( + IN CONST EFI_HANDLE TheHandle, + IN CONST BOOLEAN Verbose + ) +{ + EFI_EDID_DISCOVERED_PROTOCOL *EdidDiscovered; + EFI_STATUS Status; + CHAR16 *RetVal; + CHAR16 *Temp; + CHAR16 *TempRetVal; + + if (!Verbose) { + return (CatSPrint (NULL, L"EDIDDiscovered")); + } + + Status = gBS->OpenProtocol ( + TheHandle, + &gEfiEdidDiscoveredProtocolGuid, + (VOID**)&EdidDiscovered, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return NULL; + } + + Temp = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN (STR_EDID_DISCOVERED_MAIN), NULL); + if (Temp == NULL) { + return NULL; + } + + RetVal = CatSPrint (NULL, Temp, EdidDiscovered->SizeOfEdid); + SHELL_FREE_NON_NULL (Temp); + + if (EdidDiscovered->SizeOfEdid != 0) { + Temp = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN (STR_EDID_DISCOVERED_DATA), NULL); + if (Temp == NULL) { + SHELL_FREE_NON_NULL (RetVal); + return NULL; + } + TempRetVal = CatSPrint (RetVal, Temp); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + + TempRetVal = CatSDumpHex (RetVal, 4, 0, EdidDiscovered->SizeOfEdid, EdidDiscovered->Edid); + RetVal = TempRetVal; + } + return RetVal; +} + +/** + Function to dump information about EDID Active Protocol. + + This will allocate the return buffer from boot services pool. + + @param[in] TheHandle The handle that has LoadedImage installed. + @param[in] Verbose TRUE for additional information, FALSE otherwise. + + @retval A pointer to a string containing the information. +**/ +CHAR16* +EFIAPI +EdidActiveProtocolDumpInformation ( + IN CONST EFI_HANDLE TheHandle, + IN CONST BOOLEAN Verbose + ) +{ + EFI_EDID_ACTIVE_PROTOCOL *EdidActive; + EFI_STATUS Status; + CHAR16 *RetVal; + CHAR16 *Temp; + CHAR16 *TempRetVal; + + if (!Verbose) { + return (CatSPrint (NULL, L"EDIDActive")); + } + + Status = gBS->OpenProtocol ( + TheHandle, + &gEfiEdidActiveProtocolGuid, + (VOID**)&EdidActive, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return NULL; + } + + Temp = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN (STR_EDID_ACTIVE_MAIN), NULL); + if (Temp == NULL) { + return NULL; + } + + RetVal = CatSPrint (NULL, Temp, EdidActive->SizeOfEdid); + SHELL_FREE_NON_NULL (Temp); + + if (EdidActive->SizeOfEdid != 0) { + Temp = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN (STR_EDID_ACTIVE_DATA), NULL); + if (Temp == NULL) { + SHELL_FREE_NON_NULL (RetVal); + return NULL; + } + TempRetVal = CatSPrint (RetVal, Temp); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + + TempRetVal = CatSDumpHex (RetVal, 4, 0, EdidActive->SizeOfEdid, EdidActive->Edid); + RetVal = TempRetVal; + } + return RetVal; +} + +/** + Function to dump information about PciRootBridgeIo. + + This will allocate the return buffer from boot services pool. + + @param[in] TheHandle The handle that has PciRootBridgeIo installed. + @param[in] Verbose TRUE for additional information, FALSE otherwise. + + @retval A poitner to a string containing the information. +**/ +CHAR16* +EFIAPI +PciRootBridgeIoDumpInformation( + IN CONST EFI_HANDLE TheHandle, + IN CONST BOOLEAN Verbose + ) +{ + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration; + UINT64 Supports; + UINT64 Attributes; + CHAR16 *Temp; + CHAR16 *Temp2; + CHAR16 *RetVal; + EFI_STATUS Status; + + RetVal = NULL; + + if (!Verbose) { + return (CatSPrint(NULL, L"PciRootBridgeIo")); + } + + HandleParsingHiiInit(); + + Status = gBS->HandleProtocol( + TheHandle, + &gEfiPciRootBridgeIoProtocolGuid, + (VOID**)&PciRootBridgeIo); + + if (EFI_ERROR(Status)) { + return NULL; + } + + Temp = HiiGetString(mHandleParsingHiiHandle, STRING_TOKEN(STR_PCIRB_DUMP_PH), NULL); + if (Temp == NULL) { + return NULL; + } + Temp2 = CatSPrint(NULL, Temp, PciRootBridgeIo->ParentHandle); + FreePool(Temp); + RetVal = Temp2; + Temp2 = NULL; + + Temp = HiiGetString(mHandleParsingHiiHandle, STRING_TOKEN(STR_PCIRB_DUMP_SEG), NULL); + if (Temp == NULL) { + SHELL_FREE_NON_NULL(RetVal); + return NULL; + } + Temp2 = CatSPrint(RetVal, Temp, PciRootBridgeIo->SegmentNumber); + FreePool(Temp); + FreePool(RetVal); + RetVal = Temp2; + Temp2 = NULL; + + Supports = 0; + Attributes = 0; + Status = PciRootBridgeIo->GetAttributes (PciRootBridgeIo, &Supports, &Attributes); + if (!EFI_ERROR(Status)) { + Temp = HiiGetString(mHandleParsingHiiHandle, STRING_TOKEN(STR_PCIRB_DUMP_ATT), NULL); + if (Temp == NULL) { + SHELL_FREE_NON_NULL(RetVal); + return NULL; + } + Temp2 = CatSPrint(RetVal, Temp, Attributes); + FreePool(Temp); + FreePool(RetVal); + RetVal = Temp2; + Temp2 = NULL; + + Temp = HiiGetString(mHandleParsingHiiHandle, STRING_TOKEN(STR_PCIRB_DUMP_SUPPORTS), NULL); + if (Temp == NULL) { + SHELL_FREE_NON_NULL(RetVal); + return NULL; + } + Temp2 = CatSPrint(RetVal, Temp, Supports); + FreePool(Temp); + FreePool(RetVal); + RetVal = Temp2; + Temp2 = NULL; + } + + Configuration = NULL; + Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Configuration); + if (!EFI_ERROR(Status) && Configuration != NULL) { + Temp = HiiGetString(mHandleParsingHiiHandle, STRING_TOKEN(STR_PCIRB_DUMP_TITLE), NULL); + if (Temp == NULL) { + SHELL_FREE_NON_NULL(RetVal); + return NULL; + } + Temp2 = CatSPrint(RetVal, Temp, Supports); + FreePool(Temp); + FreePool(RetVal); + RetVal = Temp2; + Temp2 = NULL; + while (Configuration->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) { + Temp = NULL; + switch (Configuration->ResType) { + case ACPI_ADDRESS_SPACE_TYPE_MEM: + Temp = HiiGetString(mHandleParsingHiiHandle, STRING_TOKEN(STR_PCIRB_DUMP_MEM), NULL); + break; + case ACPI_ADDRESS_SPACE_TYPE_IO: + Temp = HiiGetString(mHandleParsingHiiHandle, STRING_TOKEN(STR_PCIRB_DUMP_IO), NULL); + break; + case ACPI_ADDRESS_SPACE_TYPE_BUS: + Temp = HiiGetString(mHandleParsingHiiHandle, STRING_TOKEN(STR_PCIRB_DUMP_BUS), NULL); + break; + } + if (Temp != NULL) { + Temp2 = CatSPrint(RetVal, L"\r\n%s", Temp); + FreePool(Temp); + FreePool(RetVal); + RetVal = Temp2; + Temp2 = NULL; + } + + Temp2 = CatSPrint(RetVal, + L"%%H%02x %016lx %016lx %02x%%N", + Configuration->SpecificFlag, + Configuration->AddrRangeMin, + Configuration->AddrRangeMax, + Configuration->AddrSpaceGranularity + ); + FreePool(RetVal); + RetVal = Temp2; + Temp2 = NULL; + Configuration++; + } + } + return (RetVal); +} + +/** + Function to dump information about SimpleTextOut. + + This will allocate the return buffer from boot services pool. + + @param[in] TheHandle The handle that has SimpleTextOut installed. + @param[in] Verbose TRUE for additional information, FALSE otherwise. + + @retval A poitner to a string containing the information. +**/ +CHAR16* +EFIAPI +TxtOutProtocolDumpInformation( + IN CONST EFI_HANDLE TheHandle, + IN CONST BOOLEAN Verbose + ) +{ + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Dev; + INTN Index; + UINTN Col; + UINTN Row; + EFI_STATUS Status; + CHAR16 *RetVal; + UINTN Size; + CHAR16 *Temp; + UINTN NewSize; + + if (!Verbose) { + return (NULL); + } + + HandleParsingHiiInit(); + + RetVal = NULL; + Size = 0; + + Status = gBS->HandleProtocol( + TheHandle, + &gEfiSimpleTextOutProtocolGuid, + (VOID**)&Dev); + + ASSERT_EFI_ERROR(Status); + ASSERT (Dev != NULL && Dev->Mode != NULL); + + Size = (Dev->Mode->MaxMode + 1) * 80; + RetVal = AllocateZeroPool(Size); + + Temp = HiiGetString(mHandleParsingHiiHandle, STRING_TOKEN(STR_TXT_OUT_DUMP_HEADER), NULL); + if (Temp != NULL) { + UnicodeSPrint(RetVal, Size, Temp, Dev, Dev->Mode->Attribute); + FreePool(Temp); + } + + // + // Dump TextOut Info + // + Temp = HiiGetString(mHandleParsingHiiHandle, STRING_TOKEN(STR_TXT_OUT_DUMP_LINE), NULL); + for (Index = 0; Index < Dev->Mode->MaxMode; Index++) { + Status = Dev->QueryMode (Dev, Index, &Col, &Row); + NewSize = Size - StrSize(RetVal); + UnicodeSPrint( + RetVal + StrLen(RetVal), + NewSize, + Temp == NULL?L"":Temp, + Index == Dev->Mode->Mode ? L'*' : L' ', + Index, + !EFI_ERROR(Status)?(INTN)Col:-1, + !EFI_ERROR(Status)?(INTN)Row:-1 + ); + } + FreePool(Temp); + return (RetVal); +} + +STATIC CONST UINTN VersionStringSize = 60; + +/** + Function to dump information about EfiDriverSupportedEfiVersion protocol. + + This will allocate the return buffer from boot services pool. + + @param[in] TheHandle The handle that has the protocol installed. + @param[in] Verbose TRUE for additional information, FALSE otherwise. + + @retval A poitner to a string containing the information. +**/ +CHAR16* +EFIAPI +DriverEfiVersionProtocolDumpInformation( + IN CONST EFI_HANDLE TheHandle, + IN CONST BOOLEAN Verbose + ) +{ + EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL *DriverEfiVersion; + EFI_STATUS Status; + CHAR16 *RetVal; + + Status = gBS->HandleProtocol( + TheHandle, + &gEfiDriverSupportedEfiVersionProtocolGuid, + (VOID**)&DriverEfiVersion); + + ASSERT_EFI_ERROR(Status); + + RetVal = AllocateZeroPool(VersionStringSize); + if (RetVal != NULL) { + UnicodeSPrint (RetVal, VersionStringSize, L"0x%08x", DriverEfiVersion->FirmwareVersion); + } + return (RetVal); +} +/** + Function to convert device path to string. + + This will allocate the return buffer from boot services pool. + + @param[in] DevPath Pointer to device path instance. + @param[in] Verbose TRUE for additional information, FALSE otherwise. + @param[in] Length Maximum allowed text length of the device path. + + @retval A pointer to a string containing the information. +**/ +CHAR16* +ConvertDevicePathToShortText( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevPath, + IN CONST BOOLEAN Verbose, + IN CONST UINTN Length + ) +{ + CHAR16 *Temp; + CHAR16 *Temp2; + UINTN Size; + + // + // I cannot decide whether to allow shortcuts here (the second BOOLEAN on the next line) + // + Temp = ConvertDevicePathToText(DevPath, TRUE, TRUE); + if (!Verbose && Temp != NULL && StrLen(Temp) > Length) { + Temp2 = NULL; + Size = 0; + Temp2 = StrnCatGrow(&Temp2, &Size, L"..", 0); + Temp2 = StrnCatGrow(&Temp2, &Size, Temp+(StrLen(Temp) - (Length - 2)), 0); + FreePool(Temp); + Temp = Temp2; + } + return (Temp); +} + +/** + Function to dump protocol information. + + This will allocate the return buffer from boot services pool. + + @param[in] TheHandle The handle that has the protocol installed. + @param[in] Verbose TRUE for additional information, FALSE otherwise. + @param[in] Protocol The protocol is needed to dump. + + @retval A pointer to a string containing the information. +**/ +STATIC CHAR16* +EFIAPI +DevicePathProtocolDumpInformationEx ( + IN CONST EFI_HANDLE TheHandle, + IN CONST BOOLEAN Verbose, + IN EFI_GUID *Protocol +) +{ + EFI_DEVICE_PATH_PROTOCOL *DevPath; + CHAR16 *DevPathStr; + CHAR16 *DevPathStrTemp; + UINTN Size; + EFI_STATUS Status; + DevPathStr = NULL; + DevPathStrTemp = NULL; + Status = gBS->OpenProtocol(TheHandle, Protocol, (VOID**)&DevPath, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (!EFI_ERROR(Status)) { + DevPathStr = ConvertDevicePathToShortText (DevPath, Verbose, 30); + if (Verbose) { + Size = StrSize(DevPathStr) + sizeof(CHAR16) * 2; + DevPathStrTemp = AllocateZeroPool (Size); + if (DevPathStrTemp != NULL) { + StrnCatS (DevPathStrTemp, Size/sizeof(CHAR16), L" ", 2); + StrnCatS (DevPathStrTemp, Size/sizeof(CHAR16), DevPathStr, StrLen (DevPathStr)); + } + FreePool (DevPathStr); + DevPathStr = DevPathStrTemp; + } + gBS->CloseProtocol(TheHandle, Protocol, gImageHandle, NULL); + } + return DevPathStr; +} + +/** + Function to dump information about DevicePath protocol. + + This will allocate the return buffer from boot services pool. + + @param[in] TheHandle The handle that has the protocol installed. + @param[in] Verbose TRUE for additional information, FALSE otherwise. + + @retval A pointer to a string containing the information. +**/ +CHAR16* +EFIAPI +DevicePathProtocolDumpInformation( + IN CONST EFI_HANDLE TheHandle, + IN CONST BOOLEAN Verbose + ) +{ + return DevicePathProtocolDumpInformationEx (TheHandle, Verbose, &gEfiDevicePathProtocolGuid); +} + +/** + Function to dump information about LoadedImageDevicePath protocol. + + This will allocate the return buffer from boot services pool. + + @param[in] TheHandle The handle that has the protocol installed. + @param[in] Verbose TRUE for additional information, FALSE otherwise. + + @retval A pointer to a string containing the information. +**/ +CHAR16* +EFIAPI +LoadedImageDevicePathProtocolDumpInformation( + IN CONST EFI_HANDLE TheHandle, + IN CONST BOOLEAN Verbose + ) +{ + return DevicePathProtocolDumpInformationEx (TheHandle, Verbose, &gEfiLoadedImageDevicePathProtocolGuid); +} + +/** + Function to dump information about BusSpecificDriverOverride protocol. + + This will allocate the return buffer from boot services pool. + + @param[in] TheHandle The handle that has the protocol installed. + @param[in] Verbose TRUE for additional information, FALSE otherwise. + + @retval A pointer to a string containing the information. +**/ +CHAR16* +EFIAPI +BusSpecificDriverOverrideProtocolDumpInformation ( + IN CONST EFI_HANDLE TheHandle, + IN CONST BOOLEAN Verbose + ) +{ + EFI_STATUS Status; + CHAR16 *GetString; + CHAR16 *RetVal; + CHAR16 *TempRetVal; + EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *BusSpecificDriverOverride; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + EFI_HANDLE ImageHandle; + UINTN Size; + + if (!Verbose) { + return NULL; + } + Size = 0; + GetString = NULL; + RetVal = NULL; + TempRetVal = NULL; + ImageHandle = 0; + + Status = gBS->OpenProtocol ( + TheHandle, + &gEfiBusSpecificDriverOverrideProtocolGuid, + (VOID**)&BusSpecificDriverOverride, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return NULL; + } + HandleParsingHiiInit (); + GetString = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_BSDO_DUMP_MAIN), NULL); + if (GetString == NULL) { + return NULL; + } + do { + Status = BusSpecificDriverOverride->GetDriver ( + BusSpecificDriverOverride, + &ImageHandle + ); + if (!EFI_ERROR (Status)) { + Status = gBS->HandleProtocol ( + ImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID **) &LoadedImage + ); + if(!EFI_ERROR (Status)) { + TempRetVal = CatSPrint ( + TempRetVal, + GetString, + ConvertHandleToHandleIndex (ImageHandle), + ConvertDevicePathToText (LoadedImage->FilePath, TRUE, TRUE) + ); + StrnCatGrow (&RetVal, &Size, TempRetVal, 0); + SHELL_FREE_NON_NULL (TempRetVal); + } + } + } while (!EFI_ERROR (Status)); + + SHELL_FREE_NON_NULL (GetString); + return RetVal; +} + +/** + Function to dump information about BlockIo protocol. + + This will allocate the return buffer from boot services pool. + + @param[in] TheHandle The handle that has the protocol installed. + @param[in] Verbose TRUE for additional information, FALSE otherwise. + + @retval A pointer to a string containing the information. +**/ +CHAR16* +EFIAPI +BlockIoProtocolDumpInformation ( + IN CONST EFI_HANDLE TheHandle, + IN CONST BOOLEAN Verbose + ) +{ + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_BLOCK_IO_MEDIA *BlockMedia; + CHAR16 *GetString; + CHAR16 *RetVal; + + if (!Verbose) { + return NULL; + } + GetString = NULL; + RetVal = NULL; + + Status = gBS->OpenProtocol ( + TheHandle, + &gEfiBlockIoProtocolGuid, + (VOID**)&BlockIo, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return NULL; + } + BlockMedia = BlockIo->Media; + // + // Per spec: + // The function (ReadBlocks) must return EFI_NO_MEDIA or + // EFI_MEDIA_CHANGED even if LBA, BufferSize, or Buffer are invalid so the caller can probe + // for changes in media state. + // + BlockIo->ReadBlocks ( + BlockIo, + BlockIo->Media->MediaId, + 0, + 0, + NULL + ); + + HandleParsingHiiInit (); + GetString = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_BLOCKIO_INFO), NULL); + if (GetString == NULL) { + return NULL; + } + RetVal = CatSPrint ( + RetVal, + GetString, + BlockMedia->RemovableMedia ? L"Removable " : L"Fixed ", + BlockMedia->MediaPresent ? L"" : L"not-present ", + BlockMedia->MediaId, + BlockMedia->BlockSize, + BlockMedia->LastBlock, + MultU64x32 (BlockMedia->LastBlock + 1, BlockMedia->BlockSize), + BlockMedia->LogicalPartition ? L"partition" : L"raw", + BlockMedia->ReadOnly ? L"ro" : L"rw", + BlockMedia->WriteCaching ? L"cached" : L"!cached" + ); + + SHELL_FREE_NON_NULL (GetString); + return RetVal; +} + +/** + Function to dump information about DebugSupport Protocol. + + @param[in] TheHandle The handle that has the protocol installed. + @param[in] Verbose TRUE for additional information, FALSE otherwise. + + @retval A pointer to a string containing the information. +**/ +CHAR16* +EFIAPI +DebugSupportProtocolDumpInformation ( + IN CONST EFI_HANDLE TheHandle, + IN CONST BOOLEAN Verbose + ) +{ + EFI_STATUS Status; + EFI_DEBUG_SUPPORT_PROTOCOL *DebugSupport; + CHAR16 *GetString; + CHAR16 *RetVal; + + if (!Verbose) { + return NULL; + } + GetString = NULL; + RetVal = NULL; + Status = gBS->OpenProtocol ( + TheHandle, + &gEfiDebugSupportProtocolGuid, + (VOID**)&DebugSupport, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return NULL; + } + HandleParsingHiiInit (); + GetString = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_DEBUGSUPPORT_INFO), NULL); + if (GetString == NULL) { + return NULL; + } + // + // Dump Debug support info + // + switch (DebugSupport->Isa) { + case (IsaIa32): + RetVal = CatSPrint (RetVal, GetString, L"IA-32"); + break; + case (IsaIpf): + RetVal = CatSPrint (RetVal, GetString, L"IPF"); + break; + case (IsaEbc): + RetVal = CatSPrint (RetVal, GetString, L"EBC"); + break; + default: + SHELL_FREE_NON_NULL (GetString); + GetString = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_DEBUGSUPPORT_UNKNOWN), NULL); + RetVal = GetString != NULL ? CatSPrint (RetVal, GetString, DebugSupport->Isa) : NULL; + break; + } + + SHELL_FREE_NON_NULL (GetString); + return RetVal; +} + +/** + Function to dump information about PciIoProtocol. + + This will allocate the return buffer from boot services pool. + + @param[in] TheHandle The handle that has PciRootBridgeIo installed. + @param[in] Verbose TRUE for additional information, FALSE otherwise. + + @retval A poitner to a string containing the information. +**/ +CHAR16* +EFIAPI +PciIoProtocolDumpInformation ( + IN CONST EFI_HANDLE TheHandle, + IN CONST BOOLEAN Verbose + ) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_TYPE00 Pci; + UINTN Segment; + UINTN Bus; + UINTN Device; + UINTN Function; + UINTN Index; + CHAR16 *GetString; + CHAR16 *TempRetVal; + CHAR16 *RetVal; + + if (!Verbose) { + return (NULL); + } + RetVal = NULL; + GetString = NULL; + TempRetVal = NULL; + Status = gBS->OpenProtocol ( + TheHandle, + &gEfiPciIoProtocolGuid, + (VOID**)&PciIo, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR(Status)) { + return NULL; + } + PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0, sizeof (Pci), &Pci); + PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function); + HandleParsingHiiInit (); + GetString = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_PCIIO_DUMP_MAIN), NULL); + if (GetString == NULL) { + return NULL; + } + RetVal = CatSPrint ( + NULL, + GetString, + Segment, + Bus, + Device, + Function, + PciIo->RomSize, + PciIo->RomImage, + Pci.Hdr.VendorId, + Pci.Hdr.DeviceId, + Pci.Hdr.ClassCode[0], + Pci.Hdr.ClassCode[1], + Pci.Hdr.ClassCode[2] + ); + for (Index = 0; Index < sizeof (Pci); Index ++) { + if ((Index % 0x10) == 0) { + TempRetVal = CatSPrint (RetVal, L"\r\n %02x", *((UINT8 *) (&Pci) + Index)); + } else { + TempRetVal = CatSPrint (RetVal, L"%02x", *((UINT8 *) (&Pci) + Index)); + } + FreePool (RetVal); + RetVal = TempRetVal; + TempRetVal = NULL; + } + + FreePool(GetString); + return RetVal; +} + +/** + Function to dump information about UsbIoProtocol. + + This will allocate the return buffer from boot services pool. + + @param[in] TheHandle The handle that has PciRootBridgeIo installed. + @param[in] Verbose TRUE for additional information, FALSE otherwise. + + @retval A poitner to a string containing the information. +**/ +CHAR16* +EFIAPI +UsbIoProtocolDumpInformation ( + IN CONST EFI_HANDLE TheHandle, + IN CONST BOOLEAN Verbose + ) +{ + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDesc; + CHAR16 *GetString; + CHAR16 *RetVal; + + if (!Verbose) { + return (NULL); + } + RetVal = NULL; + GetString = NULL; + Status = gBS->OpenProtocol ( + TheHandle, + &gEfiUsbIoProtocolGuid, + (VOID**)&UsbIo, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR(Status)) { + return NULL; + } + UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDesc); + HandleParsingHiiInit (); + GetString = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_USBIO_DUMP_MAIN), NULL); + if (GetString == NULL) { + return NULL; + } + RetVal = CatSPrint ( + NULL, + GetString, + InterfaceDesc.InterfaceNumber, + InterfaceDesc.InterfaceClass, + InterfaceDesc.InterfaceSubClass, + InterfaceDesc.InterfaceProtocol + ); + + FreePool (GetString); + return RetVal; +} + +/** + Function to dump information about EfiAdapterInformation Protocol. + + @param[in] TheHandle The handle that has the protocol installed. + @param[in] Verbose TRUE for additional information, FALSE otherwise. + + @retval A pointer to a string containing the information. +**/ +CHAR16* +EFIAPI +AdapterInformationDumpInformation ( + IN CONST EFI_HANDLE TheHandle, + IN CONST BOOLEAN Verbose + ) +{ + EFI_STATUS Status; + EFI_ADAPTER_INFORMATION_PROTOCOL *EfiAdptrInfoProtocol; + UINTN InfoTypesBufferCount; + UINTN GuidIndex; + EFI_GUID *InfoTypesBuffer; + CHAR16 *GuidStr; + CHAR16 *TempStr; + CHAR16 *RetVal; + CHAR16 *TempRetVal; + VOID *InformationBlock; + UINTN InformationBlockSize; + + if (!Verbose) { + return (CatSPrint(NULL, L"AdapterInfo")); + } + + InfoTypesBuffer = NULL; + InformationBlock = NULL; + + + Status = gBS->OpenProtocol ( + (EFI_HANDLE) (TheHandle), + &gEfiAdapterInformationProtocolGuid, + (VOID **) &EfiAdptrInfoProtocol, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return NULL; + } + + // + // Get a list of supported information types for this instance of the protocol. + // + Status = EfiAdptrInfoProtocol->GetSupportedTypes ( + EfiAdptrInfoProtocol, + &InfoTypesBuffer, + &InfoTypesBufferCount + ); + RetVal = NULL; + if (EFI_ERROR (Status)) { + TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_GET_SUPP_TYPES_FAILED), NULL); + if (TempStr != NULL) { + RetVal = CatSPrint (NULL, TempStr, Status); + } else { + goto ERROR_EXIT; + } + } else { + TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_SUPP_TYPE_HEADER), NULL); + if (TempStr == NULL) { + goto ERROR_EXIT; + } + RetVal = CatSPrint (NULL, TempStr); + SHELL_FREE_NON_NULL (TempStr); + + for (GuidIndex = 0; GuidIndex < InfoTypesBufferCount; GuidIndex++) { + TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_GUID_NUMBER), NULL); + if (TempStr == NULL) { + goto ERROR_EXIT; + } + TempRetVal = CatSPrint (RetVal, TempStr, (GuidIndex + 1), &InfoTypesBuffer[GuidIndex]); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + SHELL_FREE_NON_NULL (TempStr); + + TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_GUID_STRING), NULL); + if (TempStr == NULL) { + goto ERROR_EXIT; + } + + if (CompareGuid (&InfoTypesBuffer[GuidIndex], &gEfiAdapterInfoMediaStateGuid)) { + TempRetVal = CatSPrint (RetVal, TempStr, L"gEfiAdapterInfoMediaStateGuid"); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + } else if (CompareGuid (&InfoTypesBuffer[GuidIndex], &gEfiAdapterInfoNetworkBootGuid)) { + TempRetVal = CatSPrint (RetVal, TempStr, L"gEfiAdapterInfoNetworkBootGuid"); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + } else if (CompareGuid (&InfoTypesBuffer[GuidIndex], &gEfiAdapterInfoSanMacAddressGuid)) { + TempRetVal = CatSPrint (RetVal, TempStr, L"gEfiAdapterInfoSanMacAddressGuid"); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + } else if (CompareGuid (&InfoTypesBuffer[GuidIndex], &gEfiAdapterInfoUndiIpv6SupportGuid)) { + TempRetVal = CatSPrint (RetVal, TempStr, L"gEfiAdapterInfoUndiIpv6SupportGuid"); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + } else { + + GuidStr = GetStringNameFromGuid (&InfoTypesBuffer[GuidIndex], NULL); + if (GuidStr == NULL) { + TempRetVal = CatSPrint (RetVal, TempStr, L"UnknownInfoType"); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + + SHELL_FREE_NON_NULL (TempStr); + SHELL_FREE_NON_NULL(GuidStr); + // + // So that we never have to pass this UnknownInfoType to the parsing function "GetInformation" service of AIP + // + continue; + } else { + TempRetVal = CatSPrint (RetVal, TempStr, GuidStr); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + SHELL_FREE_NON_NULL(GuidStr); + } + } + + SHELL_FREE_NON_NULL (TempStr); + + Status = EfiAdptrInfoProtocol->GetInformation ( + EfiAdptrInfoProtocol, + &InfoTypesBuffer[GuidIndex], + &InformationBlock, + &InformationBlockSize + ); + + if (EFI_ERROR (Status)) { + TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_GETINFO_FAILED), NULL); + if (TempStr == NULL) { + goto ERROR_EXIT; + } + TempRetVal = CatSPrint (RetVal, TempStr, Status); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + } else { + if (CompareGuid (&InfoTypesBuffer[GuidIndex], &gEfiAdapterInfoMediaStateGuid)) { + TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_MEDIA_STATE), NULL); + if (TempStr == NULL) { + goto ERROR_EXIT; + } + TempRetVal = CatSPrint ( + RetVal, + TempStr, + ((EFI_ADAPTER_INFO_MEDIA_STATE *)InformationBlock)->MediaState, + ((EFI_ADAPTER_INFO_MEDIA_STATE *)InformationBlock)->MediaState + ); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + } else if (CompareGuid (&InfoTypesBuffer[GuidIndex], &gEfiAdapterInfoNetworkBootGuid)) { + TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_NETWORK_BOOT_INFO), NULL); + if (TempStr == NULL) { + goto ERROR_EXIT; + } + TempRetVal = CatSPrint ( + RetVal, + TempStr, + ((EFI_ADAPTER_INFO_NETWORK_BOOT *)InformationBlock)->iScsiIpv4BootCapablity, + ((EFI_ADAPTER_INFO_NETWORK_BOOT *)InformationBlock)->iScsiIpv6BootCapablity, + ((EFI_ADAPTER_INFO_NETWORK_BOOT *)InformationBlock)->FCoeBootCapablity, + ((EFI_ADAPTER_INFO_NETWORK_BOOT *)InformationBlock)->OffloadCapability, + ((EFI_ADAPTER_INFO_NETWORK_BOOT *)InformationBlock)->iScsiMpioCapability, + ((EFI_ADAPTER_INFO_NETWORK_BOOT *)InformationBlock)->iScsiIpv4Boot, + ((EFI_ADAPTER_INFO_NETWORK_BOOT *)InformationBlock)->iScsiIpv6Boot, + ((EFI_ADAPTER_INFO_NETWORK_BOOT *)InformationBlock)->FCoeBoot + ); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + } else if (CompareGuid (&InfoTypesBuffer[GuidIndex], &gEfiAdapterInfoSanMacAddressGuid) == TRUE) { + TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_SAN_MAC_ADDRESS_INFO), NULL); + if (TempStr == NULL) { + goto ERROR_EXIT; + } + TempRetVal = CatSPrint ( + RetVal, + TempStr, + ((EFI_ADAPTER_INFO_SAN_MAC_ADDRESS *)InformationBlock)->SanMacAddress.Addr[0], + ((EFI_ADAPTER_INFO_SAN_MAC_ADDRESS *)InformationBlock)->SanMacAddress.Addr[1], + ((EFI_ADAPTER_INFO_SAN_MAC_ADDRESS *)InformationBlock)->SanMacAddress.Addr[2], + ((EFI_ADAPTER_INFO_SAN_MAC_ADDRESS *)InformationBlock)->SanMacAddress.Addr[3], + ((EFI_ADAPTER_INFO_SAN_MAC_ADDRESS *)InformationBlock)->SanMacAddress.Addr[4], + ((EFI_ADAPTER_INFO_SAN_MAC_ADDRESS *)InformationBlock)->SanMacAddress.Addr[5] + ); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + } else if (CompareGuid (&InfoTypesBuffer[GuidIndex], &gEfiAdapterInfoUndiIpv6SupportGuid) == TRUE) { + TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_UNDI_IPV6_INFO), NULL); + if (TempStr == NULL) { + goto ERROR_EXIT; + } + + TempRetVal = CatSPrint ( + RetVal, + TempStr, + ((EFI_ADAPTER_INFO_UNDI_IPV6_SUPPORT *)InformationBlock)->Ipv6Support + ); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + } else { + TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_UNKNOWN_INFO_TYPE), NULL); + if (TempStr == NULL) { + goto ERROR_EXIT; + } + TempRetVal = CatSPrint (RetVal, TempStr, &InfoTypesBuffer[GuidIndex]); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + } + } + SHELL_FREE_NON_NULL (TempStr); + SHELL_FREE_NON_NULL (InformationBlock); + } + } + + SHELL_FREE_NON_NULL (InfoTypesBuffer); + return RetVal; + +ERROR_EXIT: + SHELL_FREE_NON_NULL (RetVal); + SHELL_FREE_NON_NULL (InfoTypesBuffer); + SHELL_FREE_NON_NULL (InformationBlock); + return NULL; +} + +/** + Function to dump information about EFI_FIRMWARE_MANAGEMENT_PROTOCOL Protocol. + + @param[in] TheHandle The handle that has the protocol installed. + @param[in] Verbose TRUE for additional information, FALSE otherwise. + + @retval A pointer to a string containing the information. +**/ +CHAR16* +EFIAPI +FirmwareManagementDumpInformation ( + IN CONST EFI_HANDLE TheHandle, + IN CONST BOOLEAN Verbose + ) +{ + EFI_STATUS Status; + EFI_FIRMWARE_MANAGEMENT_PROTOCOL *EfiFwMgmtProtocol; + EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo; + EFI_FIRMWARE_IMAGE_DESCRIPTOR_V1 *ImageInfoV1; + EFI_FIRMWARE_IMAGE_DESCRIPTOR_V2 *ImageInfoV2; + UINT64 AttributeSetting; + UINTN ImageInfoSize; + UINTN DescriptorSize; + UINT32 DescriptorVersion; + UINT32 PackageVersion; + UINT8 DescriptorCount; + UINT8 Index; + UINT8 Index1; + UINT8 ImageCount; + CHAR16 *PackageVersionName; + CHAR16 *TempStr; + CHAR16 *RetVal; + CHAR16 *TempRetVal; + CHAR16 *AttributeSettingStr; + BOOLEAN Found; + BOOLEAN AttributeSupported; + + // + // Initialize local variables + // + ImageCount = 0; + ImageInfoSize = 1; + AttributeSetting = 0; + Found = FALSE; + AttributeSupported = FALSE; + ImageInfo = NULL; + ImageInfoV1 = NULL; + ImageInfoV2 = NULL; + PackageVersionName = NULL; + RetVal = NULL; + TempRetVal = NULL; + TempStr = NULL; + AttributeSettingStr = NULL; + + if (!Verbose) { + return (CatSPrint(NULL, L"FirmwareManagement")); + } + + Status = gBS->OpenProtocol ( + (EFI_HANDLE) (TheHandle), + &gEfiFirmwareManagementProtocolGuid, + (VOID **) &EfiFwMgmtProtocol, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return NULL; + } + + Status = EfiFwMgmtProtocol->GetImageInfo ( + EfiFwMgmtProtocol, + &ImageInfoSize, + ImageInfo, + &DescriptorVersion, + &DescriptorCount, + &DescriptorSize, + &PackageVersion, + &PackageVersionName + ); + + if (Status == EFI_BUFFER_TOO_SMALL) { + ImageInfo = AllocateZeroPool (ImageInfoSize); + + if (ImageInfo == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + Status = EfiFwMgmtProtocol->GetImageInfo ( + EfiFwMgmtProtocol, + &ImageInfoSize, + ImageInfo, + &DescriptorVersion, + &DescriptorCount, + &DescriptorSize, + &PackageVersion, + &PackageVersionName + ); + } + } + + if (EFI_ERROR (Status)) { + goto ERROR_EXIT; + } + + // + // Decode Image Descriptor data only if its version is supported + // + if (DescriptorVersion <= EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) { + + if (ImageInfo == NULL) { + goto ERROR_EXIT; + } + + ImageInfoV1 = (EFI_FIRMWARE_IMAGE_DESCRIPTOR_V1 *)ImageInfo; + ImageInfoV2 = (EFI_FIRMWARE_IMAGE_DESCRIPTOR_V2 *)ImageInfo; + + // + // Set ImageInfoSize in return buffer + // + TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_FMP_IMAGE_INFO_SIZE), NULL); + if (TempStr == NULL) { + goto ERROR_EXIT; + } + RetVal = CatSPrint (NULL, TempStr, ImageInfoSize); + SHELL_FREE_NON_NULL (TempStr); + + // + // Set DescriptorVersion in return buffer + // + TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_FMP_DESCRIPTOR_VERSION), NULL); + if (TempStr == NULL) { + goto ERROR_EXIT; + } + TempRetVal = CatSPrint (RetVal, TempStr, DescriptorVersion); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + SHELL_FREE_NON_NULL (TempStr); + + // + // Set DescriptorCount in return buffer + // + TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_FMP_DESCRIPTOR_COUNT), NULL); + if (TempStr == NULL) { + goto ERROR_EXIT; + } + TempRetVal = CatSPrint (RetVal, TempStr, DescriptorCount); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + SHELL_FREE_NON_NULL (TempStr); + + + // + // Set DescriptorSize in return buffer + // + TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_FMP_DESCRIPTOR_SIZE), NULL); + if (TempStr == NULL) { + goto ERROR_EXIT; + } + TempRetVal = CatSPrint (RetVal, TempStr, DescriptorSize); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + SHELL_FREE_NON_NULL (TempStr); + + // + // Set PackageVersion in return buffer + // + TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_FMP_PACKAGE_VERSION), NULL); + if (TempStr == NULL) { + goto ERROR_EXIT; + } + TempRetVal = CatSPrint (RetVal, TempStr, PackageVersion); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + SHELL_FREE_NON_NULL (TempStr); + + // + // Set PackageVersionName in return buffer + // + TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_FMP_PACKAGE_VERSION_NAME), NULL); + if (TempStr == NULL) { + goto ERROR_EXIT; + } + TempRetVal = CatSPrint (RetVal, TempStr, PackageVersionName); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + SHELL_FREE_NON_NULL (TempStr); + + for (Index = 0; Index < DescriptorCount; Index++) { + // + // First check if Attribute is supported + // and generate a string for AttributeSetting field + // + SHELL_FREE_NON_NULL (AttributeSettingStr); + AttributeSupported = FALSE; + AttributeSetting = 0; + if (DescriptorVersion == EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION_V1) { + if (ImageInfoV1[Index].AttributesSupported != 0x0) { + AttributeSupported = TRUE; + AttributeSetting = ImageInfoV1[Index].AttributesSetting; + } + } else if (DescriptorVersion == EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION_V2) { + if (ImageInfoV2[Index].AttributesSupported != 0x0) { + AttributeSupported = TRUE; + AttributeSetting = ImageInfoV2[Index].AttributesSetting; + } + } else { + if (ImageInfo[Index].AttributesSupported != 0x0) { + AttributeSupported = TRUE; + AttributeSetting = ImageInfo[Index].AttributesSetting; + } + } + + if (!AttributeSupported) { + AttributeSettingStr = CatSPrint (NULL, L"None"); + } else { + AttributeSettingStr = CatSPrint (NULL, L"("); + + if ((AttributeSetting & IMAGE_ATTRIBUTE_IMAGE_UPDATABLE) != 0x0) { + TempRetVal = CatSPrint (AttributeSettingStr, L" IMAGE_ATTRIBUTE_IMAGE_UPDATABLE"); + SHELL_FREE_NON_NULL (AttributeSettingStr); + AttributeSettingStr = TempRetVal; + } + if ((AttributeSetting & IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0x0) { + TempRetVal = CatSPrint (AttributeSettingStr, L" IMAGE_ATTRIBUTE_RESET_REQUIRED"); + SHELL_FREE_NON_NULL (AttributeSettingStr); + AttributeSettingStr = TempRetVal; + } + if ((AttributeSetting & IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED) != 0x0) { + TempRetVal = CatSPrint (AttributeSettingStr, L" IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED"); + SHELL_FREE_NON_NULL (AttributeSettingStr); + AttributeSettingStr = TempRetVal; + } + if ((AttributeSetting & IMAGE_ATTRIBUTE_IN_USE) != 0x0) { + TempRetVal = CatSPrint (AttributeSettingStr, L" IMAGE_ATTRIBUTE_IN_USE"); + SHELL_FREE_NON_NULL (AttributeSettingStr); + AttributeSettingStr = TempRetVal; + } + if ((AttributeSetting & IMAGE_ATTRIBUTE_UEFI_IMAGE) != 0x0) { + TempRetVal = CatSPrint (AttributeSettingStr, L" IMAGE_ATTRIBUTE_UEFI_IMAGE"); + SHELL_FREE_NON_NULL (AttributeSettingStr); + AttributeSettingStr = TempRetVal; + } + TempRetVal = CatSPrint (AttributeSettingStr, L" )"); + SHELL_FREE_NON_NULL (AttributeSettingStr); + AttributeSettingStr = TempRetVal; + } + + if (DescriptorVersion == EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION_V1) { + if (ImageInfoV1[Index].ImageIndex != 0x0) { + ImageCount++; + } + + TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_FMP_IMAGE_DESCRIPTOR_INFO_V1), NULL); + if (TempStr == NULL) { + goto ERROR_EXIT; + } + TempRetVal = CatSPrint ( + RetVal, + TempStr, + Index, + ImageInfoV1[Index].ImageIndex, + &ImageInfoV1[Index].ImageTypeId, + ImageInfoV1[Index].ImageId, + ImageInfoV1[Index].ImageIdName, + ImageInfoV1[Index].Version, + ImageInfoV1[Index].VersionName, + ImageInfoV1[Index].Size, + ImageInfoV1[Index].AttributesSupported, + AttributeSettingStr, + ImageInfoV1[Index].Compatibilities + ); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + SHELL_FREE_NON_NULL (TempStr); + } else if (DescriptorVersion == EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION_V2) { + if (ImageInfoV2[Index].ImageIndex != 0x0) { + ImageCount++; + } + + TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_FMP_IMAGE_DESCRIPTOR_INFO_V2), NULL); + if (TempStr == NULL) { + goto ERROR_EXIT; + } + TempRetVal = CatSPrint ( + RetVal, + TempStr, + Index, + ImageInfoV2[Index].ImageIndex, + &ImageInfoV2[Index].ImageTypeId, + ImageInfoV2[Index].ImageId, + ImageInfoV2[Index].ImageIdName, + ImageInfoV2[Index].Version, + ImageInfoV2[Index].VersionName, + ImageInfoV2[Index].Size, + ImageInfoV2[Index].AttributesSupported, + AttributeSettingStr, + ImageInfoV2[Index].Compatibilities, + ImageInfoV2[Index].LowestSupportedImageVersion + ); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + SHELL_FREE_NON_NULL (TempStr); + } else { + if (ImageInfo[Index].ImageIndex != 0x0) { + ImageCount++; + } + + TempStr = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_FMP_IMAGE_DESCRIPTOR_INFO), NULL); + if (TempStr == NULL) { + goto ERROR_EXIT; + } + TempRetVal = CatSPrint ( + RetVal, + TempStr, + Index, + ImageInfo[Index].ImageIndex, + &ImageInfo[Index].ImageTypeId, + ImageInfo[Index].ImageId, + ImageInfo[Index].ImageIdName, + ImageInfo[Index].Version, + ImageInfo[Index].VersionName, + ImageInfo[Index].Size, + ImageInfo[Index].AttributesSupported, + AttributeSettingStr, + ImageInfo[Index].Compatibilities, + ImageInfo[Index].LowestSupportedImageVersion, + ImageInfo[Index].LastAttemptVersion, + ImageInfo[Index].LastAttemptStatus, + ImageInfo[Index].HardwareInstance + ); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + SHELL_FREE_NON_NULL (TempStr); + } + } + } + + if (ImageCount > 0) { + for (Index=0; IndexOpenProtocol ( + TheHandle, + &gEfiPartitionInfoProtocolGuid, + (VOID**)&PartitionInfo, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return NULL; + } + + HandleParsingHiiInit (); + + switch (PartitionInfo->Type) { + case PARTITION_TYPE_OTHER: + PartitionType = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_PARTINFO_DUMP_TYPE_OTHER), NULL); + break; + case PARTITION_TYPE_MBR: + PartitionType = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_PARTINFO_DUMP_TYPE_MBR), NULL); + break; + case PARTITION_TYPE_GPT: + PartitionType = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_PARTINFO_DUMP_TYPE_GPT), NULL); + break; + default: + PartitionType = NULL; + break; + } + if (PartitionType == NULL) { + return NULL; + } + + if (PartitionInfo->System == 1) { + EfiSystemPartition = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_PARTINFO_DUMP_EFI_SYS_PART), NULL); + } else { + EfiSystemPartition = HiiGetString (mHandleParsingHiiHandle, STRING_TOKEN(STR_PARTINFO_DUMP_NOT_EFI_SYS_PART), NULL); + } + if (EfiSystemPartition == NULL) { + SHELL_FREE_NON_NULL (PartitionType); + return NULL; + } + + RetVal = CatSPrint ( + NULL, + L"%s\r\n%s", + PartitionType, + EfiSystemPartition + ); + + SHELL_FREE_NON_NULL (EfiSystemPartition); + SHELL_FREE_NON_NULL (PartitionType); + return RetVal; +} + +// +// Put the information on the NT32 protocol GUIDs here so we are not dependant on the Nt32Pkg +// +#define LOCAL_EFI_WIN_NT_THUNK_PROTOCOL_GUID \ + { \ + 0x58c518b1, 0x76f3, 0x11d4, { 0xbc, 0xea, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } \ + } + +#define LOCAL_EFI_WIN_NT_BUS_DRIVER_IO_PROTOCOL_GUID \ + { \ + 0x96eb4ad6, 0xa32a, 0x11d4, { 0xbc, 0xfd, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } \ + } + +#define LOCAL_EFI_WIN_NT_SERIAL_PORT_GUID \ + { \ + 0xc95a93d, 0xa006, 0x11d4, { 0xbc, 0xfa, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } \ + } +STATIC CONST EFI_GUID WinNtThunkProtocolGuid = LOCAL_EFI_WIN_NT_THUNK_PROTOCOL_GUID; +STATIC CONST EFI_GUID WinNtIoProtocolGuid = LOCAL_EFI_WIN_NT_BUS_DRIVER_IO_PROTOCOL_GUID; +STATIC CONST EFI_GUID WinNtSerialPortGuid = LOCAL_EFI_WIN_NT_SERIAL_PORT_GUID; + +// +// Deprecated protocols we dont want to link from IntelFrameworkModulePkg +// +#define LOCAL_EFI_ISA_IO_PROTOCOL_GUID \ + { \ + 0x7ee2bd44, 0x3da0, 0x11d4, { 0x9a, 0x38, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } +#define LOCAL_EFI_ISA_ACPI_PROTOCOL_GUID \ + { \ + 0x64a892dc, 0x5561, 0x4536, { 0x92, 0xc7, 0x79, 0x9b, 0xfc, 0x18, 0x33, 0x55 } \ + } +STATIC CONST EFI_GUID EfiIsaIoProtocolGuid = LOCAL_EFI_ISA_IO_PROTOCOL_GUID; +STATIC CONST EFI_GUID EfiIsaAcpiProtocolGuid = LOCAL_EFI_ISA_ACPI_PROTOCOL_GUID; + + +STATIC CONST GUID_INFO_BLOCK mGuidStringListNT[] = { + {STRING_TOKEN(STR_WINNT_THUNK), (EFI_GUID*)&WinNtThunkProtocolGuid, NULL}, + {STRING_TOKEN(STR_WINNT_DRIVER_IO), (EFI_GUID*)&WinNtIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_WINNT_SERIAL_PORT), (EFI_GUID*)&WinNtSerialPortGuid, NULL}, + {0, NULL, NULL}, +}; + +STATIC CONST GUID_INFO_BLOCK mGuidStringList[] = { + {STRING_TOKEN(STR_LOADED_IMAGE), &gEfiLoadedImageProtocolGuid, LoadedImageProtocolDumpInformation}, + {STRING_TOKEN(STR_DEVICE_PATH), &gEfiDevicePathProtocolGuid, DevicePathProtocolDumpInformation}, + {STRING_TOKEN(STR_IMAGE_PATH), &gEfiLoadedImageDevicePathProtocolGuid, LoadedImageDevicePathProtocolDumpInformation}, + {STRING_TOKEN(STR_DEVICE_PATH_UTIL), &gEfiDevicePathUtilitiesProtocolGuid, NULL}, + {STRING_TOKEN(STR_DEVICE_PATH_TXT), &gEfiDevicePathToTextProtocolGuid, NULL}, + {STRING_TOKEN(STR_DEVICE_PATH_FTXT), &gEfiDevicePathFromTextProtocolGuid, NULL}, + {STRING_TOKEN(STR_DEVICE_PATH_PC), &gEfiPcAnsiGuid, NULL}, + {STRING_TOKEN(STR_DEVICE_PATH_VT100), &gEfiVT100Guid, NULL}, + {STRING_TOKEN(STR_DEVICE_PATH_VT100P), &gEfiVT100PlusGuid, NULL}, + {STRING_TOKEN(STR_DEVICE_PATH_VTUTF8), &gEfiVTUTF8Guid, NULL}, + {STRING_TOKEN(STR_DRIVER_BINDING), &gEfiDriverBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_PLATFORM_OVERRIDE), &gEfiPlatformDriverOverrideProtocolGuid, NULL}, + {STRING_TOKEN(STR_BUS_OVERRIDE), &gEfiBusSpecificDriverOverrideProtocolGuid, BusSpecificDriverOverrideProtocolDumpInformation}, + {STRING_TOKEN(STR_DRIVER_DIAG), &gEfiDriverDiagnosticsProtocolGuid, NULL}, + {STRING_TOKEN(STR_DRIVER_DIAG2), &gEfiDriverDiagnostics2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_DRIVER_CN), &gEfiComponentNameProtocolGuid, NULL}, + {STRING_TOKEN(STR_DRIVER_CN2), &gEfiComponentName2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_PLAT_DRV_CFG), &gEfiPlatformToDriverConfigurationProtocolGuid, NULL}, + {STRING_TOKEN(STR_DRIVER_VERSION), &gEfiDriverSupportedEfiVersionProtocolGuid, DriverEfiVersionProtocolDumpInformation}, + {STRING_TOKEN(STR_TXT_IN), &gEfiSimpleTextInProtocolGuid, NULL}, + {STRING_TOKEN(STR_TXT_IN_EX), &gEfiSimpleTextInputExProtocolGuid, NULL}, + {STRING_TOKEN(STR_TXT_OUT), &gEfiSimpleTextOutProtocolGuid, TxtOutProtocolDumpInformation}, + {STRING_TOKEN(STR_SIM_POINTER), &gEfiSimplePointerProtocolGuid, NULL}, + {STRING_TOKEN(STR_ABS_POINTER), &gEfiAbsolutePointerProtocolGuid, NULL}, + {STRING_TOKEN(STR_SERIAL_IO), &gEfiSerialIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_GRAPHICS_OUTPUT), &gEfiGraphicsOutputProtocolGuid, GraphicsOutputProtocolDumpInformation}, + {STRING_TOKEN(STR_EDID_DISCOVERED), &gEfiEdidDiscoveredProtocolGuid, EdidDiscoveredProtocolDumpInformation}, + {STRING_TOKEN(STR_EDID_ACTIVE), &gEfiEdidActiveProtocolGuid, EdidActiveProtocolDumpInformation}, + {STRING_TOKEN(STR_EDID_OVERRIDE), &gEfiEdidOverrideProtocolGuid, NULL}, + {STRING_TOKEN(STR_CON_IN), &gEfiConsoleInDeviceGuid, NULL}, + {STRING_TOKEN(STR_CON_OUT), &gEfiConsoleOutDeviceGuid, NULL}, + {STRING_TOKEN(STR_STD_ERR), &gEfiStandardErrorDeviceGuid, NULL}, + {STRING_TOKEN(STR_LOAD_FILE), &gEfiLoadFileProtocolGuid, NULL}, + {STRING_TOKEN(STR_LOAD_FILE2), &gEfiLoadFile2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_SIMPLE_FILE_SYS), &gEfiSimpleFileSystemProtocolGuid, NULL}, + {STRING_TOKEN(STR_TAPE_IO), &gEfiTapeIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_DISK_IO), &gEfiDiskIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_BLK_IO), &gEfiBlockIoProtocolGuid, BlockIoProtocolDumpInformation}, + {STRING_TOKEN(STR_UC), &gEfiUnicodeCollationProtocolGuid, NULL}, + {STRING_TOKEN(STR_UC2), &gEfiUnicodeCollation2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_PCIRB_IO), &gEfiPciRootBridgeIoProtocolGuid, PciRootBridgeIoDumpInformation}, + {STRING_TOKEN(STR_PCI_IO), &gEfiPciIoProtocolGuid, PciIoProtocolDumpInformation}, + {STRING_TOKEN(STR_SCSI_PT), &gEfiScsiPassThruProtocolGuid, NULL}, + {STRING_TOKEN(STR_SCSI_IO), &gEfiScsiIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_SCSI_PT_EXT), &gEfiExtScsiPassThruProtocolGuid, NULL}, + {STRING_TOKEN(STR_ISCSI), &gEfiIScsiInitiatorNameProtocolGuid, NULL}, + {STRING_TOKEN(STR_USB_IO), &gEfiUsbIoProtocolGuid, UsbIoProtocolDumpInformation}, + {STRING_TOKEN(STR_USB_HC), &gEfiUsbHcProtocolGuid, NULL}, + {STRING_TOKEN(STR_USB_HC2), &gEfiUsb2HcProtocolGuid, NULL}, + {STRING_TOKEN(STR_DEBUG_SUPPORT), &gEfiDebugSupportProtocolGuid, DebugSupportProtocolDumpInformation}, + {STRING_TOKEN(STR_DEBUG_PORT), &gEfiDebugPortProtocolGuid, NULL}, + {STRING_TOKEN(STR_DECOMPRESS), &gEfiDecompressProtocolGuid, NULL}, + {STRING_TOKEN(STR_ACPI_TABLE), &gEfiAcpiTableProtocolGuid, NULL}, + {STRING_TOKEN(STR_EBC_INTERPRETER), &gEfiEbcProtocolGuid, NULL}, + {STRING_TOKEN(STR_SNP), &gEfiSimpleNetworkProtocolGuid, NULL}, + {STRING_TOKEN(STR_NII), &gEfiNetworkInterfaceIdentifierProtocolGuid, NULL}, + {STRING_TOKEN(STR_NII_31), &gEfiNetworkInterfaceIdentifierProtocolGuid_31, NULL}, + {STRING_TOKEN(STR_PXE_BC), &gEfiPxeBaseCodeProtocolGuid, NULL}, + {STRING_TOKEN(STR_PXE_CB), &gEfiPxeBaseCodeCallbackProtocolGuid, NULL}, + {STRING_TOKEN(STR_BIS), &gEfiBisProtocolGuid, NULL}, + {STRING_TOKEN(STR_MNP_SB), &gEfiManagedNetworkServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_MNP), &gEfiManagedNetworkProtocolGuid, NULL}, + {STRING_TOKEN(STR_ARP_SB), &gEfiArpServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_ARP), &gEfiArpProtocolGuid, NULL}, + {STRING_TOKEN(STR_DHCPV4_SB), &gEfiDhcp4ServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_DHCPV4), &gEfiDhcp4ProtocolGuid, NULL}, + {STRING_TOKEN(STR_TCPV4_SB), &gEfiTcp4ServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_TCPV4), &gEfiTcp4ProtocolGuid, NULL}, + {STRING_TOKEN(STR_IPV4_SB), &gEfiIp4ServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_IPV4), &gEfiIp4ProtocolGuid, NULL}, + {STRING_TOKEN(STR_IPV4_CFG), &gEfiIp4ConfigProtocolGuid, NULL}, + {STRING_TOKEN(STR_IPV4_CFG2), &gEfiIp4Config2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_UDPV4_SB), &gEfiUdp4ServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_UDPV4), &gEfiUdp4ProtocolGuid, NULL}, + {STRING_TOKEN(STR_MTFTPV4_SB), &gEfiMtftp4ServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_MTFTPV4), &gEfiMtftp4ProtocolGuid, NULL}, + {STRING_TOKEN(STR_AUTH_INFO), &gEfiAuthenticationInfoProtocolGuid, NULL}, + {STRING_TOKEN(STR_HASH_SB), &gEfiHashServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_HASH), &gEfiHashProtocolGuid, NULL}, + {STRING_TOKEN(STR_HII_FONT), &gEfiHiiFontProtocolGuid, NULL}, + {STRING_TOKEN(STR_HII_STRING), &gEfiHiiStringProtocolGuid, NULL}, + {STRING_TOKEN(STR_HII_IMAGE), &gEfiHiiImageProtocolGuid, NULL}, + {STRING_TOKEN(STR_HII_DATABASE), &gEfiHiiDatabaseProtocolGuid, NULL}, + {STRING_TOKEN(STR_HII_CONFIG_ROUT), &gEfiHiiConfigRoutingProtocolGuid, NULL}, + {STRING_TOKEN(STR_HII_CONFIG_ACC), &gEfiHiiConfigAccessProtocolGuid, NULL}, + {STRING_TOKEN(STR_HII_FORM_BROWSER2), &gEfiFormBrowser2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_DRIVER_FAM_OVERRIDE), &gEfiDriverFamilyOverrideProtocolGuid, NULL}, + {STRING_TOKEN(STR_PCD), &gPcdProtocolGuid, NULL}, + {STRING_TOKEN(STR_TCG), &gEfiTcgProtocolGuid, NULL}, + {STRING_TOKEN(STR_HII_PACKAGE_LIST), &gEfiHiiPackageListProtocolGuid, NULL}, + +// +// the ones under this are deprecated by the current UEFI Spec, but may be found anyways... +// + {STRING_TOKEN(STR_SHELL_INTERFACE), &gEfiShellInterfaceGuid, NULL}, + {STRING_TOKEN(STR_SHELL_ENV2), &gEfiShellEnvironment2Guid, NULL}, + {STRING_TOKEN(STR_SHELL_ENV), &gEfiShellEnvironment2Guid, NULL}, + {STRING_TOKEN(STR_DEVICE_IO), &gEfiDeviceIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_UGA_DRAW), &gEfiUgaDrawProtocolGuid, NULL}, + {STRING_TOKEN(STR_UGA_IO), &gEfiUgaIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_ESP), &gEfiPartTypeSystemPartGuid, NULL}, + {STRING_TOKEN(STR_GPT_NBR), &gEfiPartTypeLegacyMbrGuid, NULL}, + {STRING_TOKEN(STR_DRIVER_CONFIG), &gEfiDriverConfigurationProtocolGuid, NULL}, + {STRING_TOKEN(STR_DRIVER_CONFIG2), &gEfiDriverConfiguration2ProtocolGuid, NULL}, + +// +// these are using local (non-global) definitions to reduce package dependancy. +// + {STRING_TOKEN(STR_ISA_IO), (EFI_GUID*)&EfiIsaIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_ISA_ACPI), (EFI_GUID*)&EfiIsaAcpiProtocolGuid, NULL}, + +// +// the ones under this are GUID identified structs, not protocols +// + {STRING_TOKEN(STR_FILE_INFO), &gEfiFileInfoGuid, NULL}, + {STRING_TOKEN(STR_FILE_SYS_INFO), &gEfiFileSystemInfoGuid, NULL}, + +// +// the ones under this are misc GUIDS. +// + {STRING_TOKEN(STR_EFI_GLOBAL_VARIABLE), &gEfiGlobalVariableGuid, NULL}, + +// +// UEFI 2.2 +// + {STRING_TOKEN(STR_IP6_SB), &gEfiIp6ServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_IP6), &gEfiIp6ProtocolGuid, NULL}, + {STRING_TOKEN(STR_IP6_CONFIG), &gEfiIp6ConfigProtocolGuid, NULL}, + {STRING_TOKEN(STR_MTFTP6_SB), &gEfiMtftp6ServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_MTFTP6), &gEfiMtftp6ProtocolGuid, NULL}, + {STRING_TOKEN(STR_DHCP6_SB), &gEfiDhcp6ServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_DHCP6), &gEfiDhcp6ProtocolGuid, NULL}, + {STRING_TOKEN(STR_UDP6_SB), &gEfiUdp6ServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_UDP6), &gEfiUdp6ProtocolGuid, NULL}, + {STRING_TOKEN(STR_TCP6_SB), &gEfiTcp6ServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_TCP6), &gEfiTcp6ProtocolGuid, NULL}, + {STRING_TOKEN(STR_VLAN_CONFIG), &gEfiVlanConfigProtocolGuid, NULL}, + {STRING_TOKEN(STR_EAP), &gEfiEapProtocolGuid, NULL}, + {STRING_TOKEN(STR_EAP_MGMT), &gEfiEapManagementProtocolGuid, NULL}, + {STRING_TOKEN(STR_FTP4_SB), &gEfiFtp4ServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_FTP4), &gEfiFtp4ProtocolGuid, NULL}, + {STRING_TOKEN(STR_IP_SEC_CONFIG), &gEfiIpSecConfigProtocolGuid, NULL}, + {STRING_TOKEN(STR_DH), &gEfiDriverHealthProtocolGuid, NULL}, + {STRING_TOKEN(STR_DEF_IMG_LOAD), &gEfiDeferredImageLoadProtocolGuid, NULL}, + {STRING_TOKEN(STR_USER_CRED), &gEfiUserCredentialProtocolGuid, NULL}, + {STRING_TOKEN(STR_USER_MNGR), &gEfiUserManagerProtocolGuid, NULL}, + {STRING_TOKEN(STR_ATA_PASS_THRU), &gEfiAtaPassThruProtocolGuid, NULL}, + +// +// UEFI 2.3 +// + {STRING_TOKEN(STR_FW_MGMT), &gEfiFirmwareManagementProtocolGuid, FirmwareManagementDumpInformation}, + {STRING_TOKEN(STR_IP_SEC), &gEfiIpSecProtocolGuid, NULL}, + {STRING_TOKEN(STR_IP_SEC2), &gEfiIpSec2ProtocolGuid, NULL}, + +// +// UEFI 2.3.1 +// + {STRING_TOKEN(STR_KMS), &gEfiKmsProtocolGuid, NULL}, + {STRING_TOKEN(STR_BLK_IO2), &gEfiBlockIo2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_SSC), &gEfiStorageSecurityCommandProtocolGuid, NULL}, + {STRING_TOKEN(STR_UCRED2), &gEfiUserCredential2ProtocolGuid, NULL}, + +// +// UEFI 2.4 +// + {STRING_TOKEN(STR_DISK_IO2), &gEfiDiskIo2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_ADAPTER_INFO), &gEfiAdapterInformationProtocolGuid, AdapterInformationDumpInformation}, + +// +// UEFI2.5 +// + {STRING_TOKEN(STR_TLS_SB), &gEfiTlsServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_TLS), &gEfiTlsProtocolGuid, NULL}, + {STRING_TOKEN(STR_TLS_CONFIG), &gEfiTlsConfigurationProtocolGuid, NULL}, + {STRING_TOKEN(STR_SUPPLICANT_SB), &gEfiSupplicantServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_SUPPLICANT), &gEfiSupplicantProtocolGuid, NULL}, + +// +// UEFI2.6 +// + {STRING_TOKEN(STR_WIFI2), &gEfiWiFi2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_RAMDISK), &gEfiRamDiskProtocolGuid, NULL}, + {STRING_TOKEN(STR_HII_ID), &gEfiHiiImageDecoderProtocolGuid, NULL}, + {STRING_TOKEN(STR_HII_IE), &gEfiHiiImageExProtocolGuid, NULL}, + {STRING_TOKEN(STR_SD_MPT), &gEfiSdMmcPassThruProtocolGuid, NULL}, + {STRING_TOKEN(STR_ERASE_BLOCK), &gEfiEraseBlockProtocolGuid, NULL}, + +// +// UEFI2.7 +// + {STRING_TOKEN(STR_BLUETOOTH_ATTR), &gEfiBluetoothAttributeProtocolGuid, NULL}, + {STRING_TOKEN(STR_BLUETOOTH_ATTR_SB), &gEfiBluetoothAttributeServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_BLUETOOTH_LE_CONFIG), &gEfiBluetoothLeConfigProtocolGuid, NULL}, + {STRING_TOKEN(STR_UFS_DEV_CONFIG), &gEfiUfsDeviceConfigProtocolGuid, NULL}, + {STRING_TOKEN(STR_HTTP_BOOT_CALL), &gEfiHttpBootCallbackProtocolGuid, NULL}, + {STRING_TOKEN(STR_RESET_NOTI), &gEfiResetNotificationProtocolGuid, NULL}, + {STRING_TOKEN(STR_PARTITION_INFO), &gEfiPartitionInfoProtocolGuid, PartitionInfoProtocolDumpInformation}, + {STRING_TOKEN(STR_HII_POPUP), &gEfiHiiPopupProtocolGuid, NULL}, + +// +// UEFI 2.8 +// + {STRING_TOKEN(STR_REST_EX), &gEfiRestExProtocolGuid, NULL}, + {STRING_TOKEN(STR_REDFISH_DISCOVER), &gEfiRedfishDiscoverProtocolGuid, NULL}, + +// +// PI Spec ones +// + {STRING_TOKEN(STR_IDE_CONT_INIT), &gEfiIdeControllerInitProtocolGuid, NULL}, + {STRING_TOKEN(STR_DISK_INFO), &gEfiDiskInfoProtocolGuid, NULL}, + +// +// PI Spec 1.0 +// + {STRING_TOKEN(STR_BDS_ARCH), &gEfiBdsArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_CPU_ARCH), &gEfiCpuArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_MET_ARCH), &gEfiMetronomeArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_MON_ARCH), &gEfiMonotonicCounterArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_RTC_ARCH), &gEfiRealTimeClockArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_RESET_ARCH), &gEfiResetArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_RT_ARCH), &gEfiRuntimeArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_SEC_ARCH), &gEfiSecurityArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_TIMER_ARCH), &gEfiTimerArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_VAR_ARCH), &gEfiVariableWriteArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_V_ARCH), &gEfiVariableArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_SECP), &gEfiSecurityPolicyProtocolGuid, NULL}, + {STRING_TOKEN(STR_WDT_ARCH), &gEfiWatchdogTimerArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_SCR), &gEfiStatusCodeRuntimeProtocolGuid, NULL}, + {STRING_TOKEN(STR_SMB_HC), &gEfiSmbusHcProtocolGuid, NULL}, + {STRING_TOKEN(STR_FV_2), &gEfiFirmwareVolume2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_FV_BLOCK), &gEfiFirmwareVolumeBlockProtocolGuid, NULL}, + {STRING_TOKEN(STR_CAP_ARCH), &gEfiCapsuleArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_MP_SERVICE), &gEfiMpServiceProtocolGuid, NULL}, + {STRING_TOKEN(STR_HBRAP), &gEfiPciHostBridgeResourceAllocationProtocolGuid, NULL}, + {STRING_TOKEN(STR_PCIP), &gEfiPciPlatformProtocolGuid, NULL}, + {STRING_TOKEN(STR_PCIO), &gEfiPciOverrideProtocolGuid, NULL}, + {STRING_TOKEN(STR_PCIE), &gEfiPciEnumerationCompleteProtocolGuid, NULL}, + {STRING_TOKEN(STR_IPCID), &gEfiIncompatiblePciDeviceSupportProtocolGuid, NULL}, + {STRING_TOKEN(STR_PCIHPI), &gEfiPciHotPlugInitProtocolGuid, NULL}, + {STRING_TOKEN(STR_PCIHPR), &gEfiPciHotPlugRequestProtocolGuid, NULL}, + {STRING_TOKEN(STR_SMBIOS), &gEfiSmbiosProtocolGuid, NULL}, + {STRING_TOKEN(STR_S3_SAVE), &gEfiS3SaveStateProtocolGuid, NULL}, + {STRING_TOKEN(STR_S3_S_SMM), &gEfiS3SmmSaveStateProtocolGuid, NULL}, + {STRING_TOKEN(STR_RSC), &gEfiRscHandlerProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_RSC), &gEfiSmmRscHandlerProtocolGuid, NULL}, + {STRING_TOKEN(STR_ACPI_SDT), &gEfiAcpiSdtProtocolGuid, NULL}, + {STRING_TOKEN(STR_SIO), &gEfiSioProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_CPU2), &gEfiSmmCpuIo2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_BASE2), &gEfiSmmBase2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_ACC_2), &gEfiSmmAccess2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_CON_2), &gEfiSmmControl2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_CONFIG), &gEfiSmmConfigurationProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_RTL), &gEfiSmmReadyToLockProtocolGuid, NULL}, + {STRING_TOKEN(STR_DS_RTL), &gEfiDxeSmmReadyToLockProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_COMM), &gEfiSmmCommunicationProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_STAT), &gEfiSmmStatusCodeProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_CPU), &gEfiSmmCpuProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_PCIRBIO), &gEfiSmmPciRootBridgeIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_SWD), &gEfiSmmSwDispatch2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_SXD), &gEfiSmmSxDispatch2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_PTD2), &gEfiSmmPeriodicTimerDispatch2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_UD2), &gEfiSmmUsbDispatch2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_GD2), &gEfiSmmGpiDispatch2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_SBD2), &gEfiSmmStandbyButtonDispatch2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_PBD2), &gEfiSmmPowerButtonDispatch2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_S_ITD2), &gEfiSmmIoTrapDispatch2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_PCD), &gEfiPcdProtocolGuid, NULL}, + {STRING_TOKEN(STR_FVB2), &gEfiFirmwareVolumeBlock2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_CPUIO2), &gEfiCpuIo2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_LEGACY_R2), &gEfiLegacyRegion2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_S2ARCH), &gEfiSecurity2ArchProtocolGuid, NULL}, + {STRING_TOKEN(STR_EODXE), &gEfiSmmEndOfDxeProtocolGuid, NULL}, + {STRING_TOKEN(STR_ISAHC), &gEfiIsaHcProtocolGuid, NULL}, + {STRING_TOKEN(STR_ISAHC_B), &gEfiIsaHcServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_SIO_C), &gEfiSioControlProtocolGuid, NULL}, + {STRING_TOKEN(STR_GET_PCD), &gEfiGetPcdInfoProtocolGuid, NULL}, + {STRING_TOKEN(STR_I2C_M), &gEfiI2cMasterProtocolGuid, NULL}, + {STRING_TOKEN(STR_I2CIO), &gEfiI2cIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_I2CEN), &gEfiI2cEnumerateProtocolGuid, NULL}, + {STRING_TOKEN(STR_I2C_H), &gEfiI2cHostProtocolGuid, NULL}, + {STRING_TOKEN(STR_I2C_BCM), &gEfiI2cBusConfigurationManagementProtocolGuid, NULL}, + {STRING_TOKEN(STR_TCG2), &gEfiTcg2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_TIMESTAMP), &gEfiTimestampProtocolGuid, NULL}, + {STRING_TOKEN(STR_RNG), &gEfiRngProtocolGuid, NULL}, + {STRING_TOKEN(STR_NVMEPT), &gEfiNvmExpressPassThruProtocolGuid, NULL}, + {STRING_TOKEN(STR_H2_SB), &gEfiHash2ServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_HASH2), &gEfiHash2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_BIO_C), &gEfiBlockIoCryptoProtocolGuid, NULL}, + {STRING_TOKEN(STR_SCR), &gEfiSmartCardReaderProtocolGuid, NULL}, + {STRING_TOKEN(STR_SCE), &gEfiSmartCardEdgeProtocolGuid, NULL}, + {STRING_TOKEN(STR_USB_FIO), &gEfiUsbFunctionIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_BC_HC), &gEfiBluetoothHcProtocolGuid, NULL}, + {STRING_TOKEN(STR_BC_IO_SB), &gEfiBluetoothIoServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_BC_IO), &gEfiBluetoothIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_BC_C), &gEfiBluetoothConfigProtocolGuid, NULL}, + {STRING_TOKEN(STR_REG_EXP), &gEfiRegularExpressionProtocolGuid, NULL}, + {STRING_TOKEN(STR_B_MGR_P), &gEfiBootManagerPolicyProtocolGuid, NULL}, + {STRING_TOKEN(STR_CKH), &gEfiConfigKeywordHandlerProtocolGuid, NULL}, + {STRING_TOKEN(STR_WIFI), &gEfiWiFiProtocolGuid, NULL}, + {STRING_TOKEN(STR_EAP_M), &gEfiEapManagement2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_EAP_C), &gEfiEapConfigurationProtocolGuid, NULL}, + {STRING_TOKEN(STR_PKCS7), &gEfiPkcs7VerifyProtocolGuid, NULL}, + {STRING_TOKEN(STR_NET_DNS4_SB), &gEfiDns4ServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_NET_DNS4), &gEfiDns4ProtocolGuid, NULL}, + {STRING_TOKEN(STR_NET_DNS6_SB), &gEfiDns6ServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_NET_DNS6), &gEfiDns6ProtocolGuid, NULL}, + {STRING_TOKEN(STR_NET_HTTP_SB), &gEfiHttpServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_NET_HTTP), &gEfiHttpProtocolGuid, NULL}, + {STRING_TOKEN(STR_NET_HTTP_U), &gEfiHttpUtilitiesProtocolGuid, NULL}, + {STRING_TOKEN(STR_REST), &gEfiRestProtocolGuid, NULL}, + +// +// PI 1.5 +// + {STRING_TOKEN(STR_MM_EOD), &gEfiMmEndOfDxeProtocolGuid, NULL}, + {STRING_TOKEN(STR_MM_ITD), &gEfiMmIoTrapDispatchProtocolGuid, NULL}, + {STRING_TOKEN(STR_MM_PBD), &gEfiMmPowerButtonDispatchProtocolGuid, NULL}, + {STRING_TOKEN(STR_MM_SBD), &gEfiMmStandbyButtonDispatchProtocolGuid, NULL}, + {STRING_TOKEN(STR_MM_GD), &gEfiMmGpiDispatchProtocolGuid, NULL}, + {STRING_TOKEN(STR_MM_UD), &gEfiMmUsbDispatchProtocolGuid, NULL}, + {STRING_TOKEN(STR_MM_PTD), &gEfiMmPeriodicTimerDispatchProtocolGuid, NULL}, + {STRING_TOKEN(STR_MM_SXD), &gEfiMmSxDispatchProtocolGuid, NULL}, + {STRING_TOKEN(STR_MM_SWD), &gEfiMmSwDispatchProtocolGuid, NULL}, + {STRING_TOKEN(STR_MM_PRBI), &gEfiMmPciRootBridgeIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_MM_CPU), &gEfiMmCpuProtocolGuid, NULL}, + {STRING_TOKEN(STR_MM_STACODE), &gEfiMmStatusCodeProtocolGuid, NULL}, + {STRING_TOKEN(STR_DXEMM_RTL), &gEfiDxeMmReadyToLockProtocolGuid, NULL}, + {STRING_TOKEN(STR_MM_CONFIG), &gEfiMmConfigurationProtocolGuid, NULL}, + {STRING_TOKEN(STR_MM_RTL), &gEfiMmReadyToLockProtocolGuid, NULL}, + {STRING_TOKEN(STR_MM_CONTROL), &gEfiMmControlProtocolGuid, NULL}, + {STRING_TOKEN(STR_MM_ACCESS), &gEfiMmAccessProtocolGuid, NULL}, + {STRING_TOKEN(STR_MM_BASE), &gEfiMmBaseProtocolGuid, NULL}, + {STRING_TOKEN(STR_MM_CPUIO), &gEfiMmCpuIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_MM_RH), &gEfiMmRscHandlerProtocolGuid, NULL}, + {STRING_TOKEN(STR_MM_COM), &gEfiMmCommunicationProtocolGuid, NULL}, + +// +// UEFI Shell Spec 2.0 +// + {STRING_TOKEN(STR_SHELL_PARAMETERS), &gEfiShellParametersProtocolGuid, NULL}, + {STRING_TOKEN(STR_SHELL), &gEfiShellProtocolGuid, NULL}, + +// +// UEFI Shell Spec 2.1 +// + {STRING_TOKEN(STR_SHELL_DYNAMIC), &gEfiShellDynamicCommandProtocolGuid, NULL}, + +// +// Misc +// + {STRING_TOKEN(STR_PCDINFOPROT), &gGetPcdInfoProtocolGuid, NULL}, + +// +// terminator +// + {0, NULL, NULL}, +}; + +/** + Function to get the node for a protocol or struct from it's GUID. + + if Guid is NULL, then ASSERT. + + @param[in] Guid The GUID to look for the name of. + + @return The node. +**/ +CONST GUID_INFO_BLOCK * +InternalShellGetNodeFromGuid( + IN CONST EFI_GUID* Guid + ) +{ + CONST GUID_INFO_BLOCK *ListWalker; + UINTN LoopCount; + + ASSERT(Guid != NULL); + + for (LoopCount = 0, ListWalker = mGuidList; mGuidList != NULL && LoopCount < mGuidListCount; LoopCount++, ListWalker++) { + if (CompareGuid(ListWalker->GuidId, Guid)) { + return (ListWalker); + } + } + + if (PcdGetBool(PcdShellIncludeNtGuids)) { + for (ListWalker = mGuidStringListNT ; ListWalker != NULL && ListWalker->GuidId != NULL ; ListWalker++) { + if (CompareGuid(ListWalker->GuidId, Guid)) { + return (ListWalker); + } + } + } + for (ListWalker = mGuidStringList ; ListWalker != NULL && ListWalker->GuidId != NULL ; ListWalker++) { + if (CompareGuid(ListWalker->GuidId, Guid)) { + return (ListWalker); + } + } + return (NULL); +} + +/** +Function to add a new GUID/Name mapping. + +@param[in] Guid The Guid +@param[in] NameID The STRING id of the HII string to use +@param[in] DumpFunc The pointer to the dump function + + +@retval EFI_SUCCESS The operation was sucessful +@retval EFI_OUT_OF_RESOURCES A memory allocation failed +@retval EFI_INVALID_PARAMETER Guid NameId was invalid +**/ +EFI_STATUS +InsertNewGuidNameMapping( + IN CONST EFI_GUID *Guid, + IN CONST EFI_STRING_ID NameID, + IN CONST DUMP_PROTOCOL_INFO DumpFunc OPTIONAL + ) +{ + ASSERT (Guid != NULL); + ASSERT (NameID != 0); + + mGuidList = ReallocatePool ( + mGuidListCount * sizeof (GUID_INFO_BLOCK), + (mGuidListCount + 1) * sizeof (GUID_INFO_BLOCK), + mGuidList + ); + if (mGuidList == NULL) { + mGuidListCount = 0; + return (EFI_OUT_OF_RESOURCES); + } + mGuidListCount++; + + mGuidList[mGuidListCount - 1].GuidId = AllocateCopyPool (sizeof (EFI_GUID), Guid); + mGuidList[mGuidListCount - 1].StringId = NameID; + mGuidList[mGuidListCount - 1].DumpInfo = DumpFunc; + + if (mGuidList[mGuidListCount - 1].GuidId == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + return (EFI_SUCCESS); +} + +/** + Function to add a new GUID/Name mapping. + + This cannot overwrite an existing mapping. + + @param[in] Guid The Guid + @param[in] TheName The Guid's name + @param[in] Lang RFC4646 language code list or NULL + + @retval EFI_SUCCESS The operation was sucessful + @retval EFI_ACCESS_DENIED There was a duplicate + @retval EFI_OUT_OF_RESOURCES A memory allocation failed + @retval EFI_INVALID_PARAMETER Guid or TheName was NULL +**/ +EFI_STATUS +EFIAPI +AddNewGuidNameMapping( + IN CONST EFI_GUID *Guid, + IN CONST CHAR16 *TheName, + IN CONST CHAR8 *Lang OPTIONAL + ) +{ + EFI_STRING_ID NameID; + + HandleParsingHiiInit(); + + if (Guid == NULL || TheName == NULL){ + return (EFI_INVALID_PARAMETER); + } + + if ((InternalShellGetNodeFromGuid(Guid)) != NULL) { + return (EFI_ACCESS_DENIED); + } + + NameID = HiiSetString(mHandleParsingHiiHandle, 0, (CHAR16*)TheName, Lang); + if (NameID == 0) { + return (EFI_OUT_OF_RESOURCES); + } + + return (InsertNewGuidNameMapping(Guid, NameID, NULL)); +} + +/** + Function to get the name of a protocol or struct from it's GUID. + + if Guid is NULL, then ASSERT. + + @param[in] Guid The GUID to look for the name of. + @param[in] Lang The language to use. + + @return pointer to string of the name. The caller + is responsible to free this memory. +**/ +CHAR16* +EFIAPI +GetStringNameFromGuid( + IN CONST EFI_GUID *Guid, + IN CONST CHAR8 *Lang OPTIONAL + ) +{ + CONST GUID_INFO_BLOCK *Id; + + HandleParsingHiiInit(); + + Id = InternalShellGetNodeFromGuid(Guid); + if (Id == NULL) { + return NULL; + } + return HiiGetString (mHandleParsingHiiHandle, Id->StringId, Lang); +} + +/** + Function to dump protocol information from a handle. + + This function will return a allocated string buffer containing the + information. The caller is responsible for freeing the memory. + + If Guid is NULL, ASSERT(). + If TheHandle is NULL, ASSERT(). + + @param[in] TheHandle The handle to dump information from. + @param[in] Guid The GUID of the protocol to dump. + @param[in] Verbose TRUE for extra info. FALSE otherwise. + + @return The pointer to string. + @retval NULL An error was encountered. +**/ +CHAR16* +EFIAPI +GetProtocolInformationDump( + IN CONST EFI_HANDLE TheHandle, + IN CONST EFI_GUID *Guid, + IN CONST BOOLEAN Verbose + ) +{ + CONST GUID_INFO_BLOCK *Id; + + ASSERT(TheHandle != NULL); + ASSERT(Guid != NULL); + + if (TheHandle == NULL || Guid == NULL) { + return (NULL); + } + + Id = InternalShellGetNodeFromGuid(Guid); + if (Id != NULL && Id->DumpInfo != NULL) { + return (Id->DumpInfo(TheHandle, Verbose)); + } + return (NULL); +} + +/** + Function to get the Guid for a protocol or struct based on it's string name. + + do not modify the returned Guid. + + @param[in] Name The pointer to the string name. + @param[in] Lang The pointer to the language code. + @param[out] Guid The pointer to the Guid. + + @retval EFI_SUCCESS The operation was sucessful. +**/ +EFI_STATUS +EFIAPI +GetGuidFromStringName( + IN CONST CHAR16 *Name, + IN CONST CHAR8 *Lang OPTIONAL, + OUT EFI_GUID **Guid + ) +{ + CONST GUID_INFO_BLOCK *ListWalker; + CHAR16 *String; + UINTN LoopCount; + + HandleParsingHiiInit(); + + ASSERT(Guid != NULL); + if (Guid == NULL) { + return (EFI_INVALID_PARAMETER); + } + *Guid = NULL; + + if (PcdGetBool(PcdShellIncludeNtGuids)) { + for (ListWalker = mGuidStringListNT ; ListWalker != NULL && ListWalker->GuidId != NULL ; ListWalker++) { + String = HiiGetString(mHandleParsingHiiHandle, ListWalker->StringId, Lang); + if (Name != NULL && String != NULL && StringNoCaseCompare (&Name, &String) == 0) { + *Guid = ListWalker->GuidId; + } + SHELL_FREE_NON_NULL(String); + if (*Guid != NULL) { + return (EFI_SUCCESS); + } + } + } + for (ListWalker = mGuidStringList ; ListWalker != NULL && ListWalker->GuidId != NULL ; ListWalker++) { + String = HiiGetString(mHandleParsingHiiHandle, ListWalker->StringId, Lang); + if (Name != NULL && String != NULL && StringNoCaseCompare (&Name, &String) == 0) { + *Guid = ListWalker->GuidId; + } + SHELL_FREE_NON_NULL(String); + if (*Guid != NULL) { + return (EFI_SUCCESS); + } + } + + for (LoopCount = 0, ListWalker = mGuidList; mGuidList != NULL && LoopCount < mGuidListCount; LoopCount++, ListWalker++) { + String = HiiGetString(mHandleParsingHiiHandle, ListWalker->StringId, Lang); + if (Name != NULL && String != NULL && StringNoCaseCompare (&Name, &String) == 0) { + *Guid = ListWalker->GuidId; + } + SHELL_FREE_NON_NULL(String); + if (*Guid != NULL) { + return (EFI_SUCCESS); + } + } + + return (EFI_NOT_FOUND); +} + +/** + Get best support language for this driver. + + First base on the user input language to search, second base on the current + platform used language to search, third get the first language from the + support language list. The caller need to free the buffer of the best language. + + @param[in] SupportedLanguages The support languages for this driver. + @param[in] InputLanguage The user input language. + @param[in] Iso639Language Whether get language for ISO639. + + @return The best support language for this driver. +**/ +CHAR8 * +EFIAPI +GetBestLanguageForDriver ( + IN CONST CHAR8 *SupportedLanguages, + IN CONST CHAR8 *InputLanguage, + IN BOOLEAN Iso639Language + ) +{ + CHAR8 *LanguageVariable; + CHAR8 *BestLanguage; + + GetVariable2 (Iso639Language ? L"Lang" : L"PlatformLang", &gEfiGlobalVariableGuid, (VOID**)&LanguageVariable, NULL); + + BestLanguage = GetBestLanguage( + SupportedLanguages, + Iso639Language, + (InputLanguage != NULL) ? InputLanguage : "", + (LanguageVariable != NULL) ? LanguageVariable : "", + SupportedLanguages, + NULL + ); + + if (LanguageVariable != NULL) { + FreePool (LanguageVariable); + } + + return BestLanguage; +} + +/** + Function to retrieve the driver name (if possible) from the ComponentName or + ComponentName2 protocol + + @param[in] TheHandle The driver handle to get the name of. + @param[in] Language The language to use. + + @retval NULL The name could not be found. + @return A pointer to the string name. Do not de-allocate the memory. +**/ +CONST CHAR16* +EFIAPI +GetStringNameFromHandle( + IN CONST EFI_HANDLE TheHandle, + IN CONST CHAR8 *Language + ) +{ + EFI_COMPONENT_NAME2_PROTOCOL *CompNameStruct; + EFI_STATUS Status; + CHAR16 *RetVal; + CHAR8 *BestLang; + + BestLang = NULL; + + Status = gBS->OpenProtocol( + TheHandle, + &gEfiComponentName2ProtocolGuid, + (VOID**)&CompNameStruct, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (!EFI_ERROR(Status)) { + BestLang = GetBestLanguageForDriver (CompNameStruct->SupportedLanguages, Language, FALSE); + Status = CompNameStruct->GetDriverName(CompNameStruct, BestLang, &RetVal); + if (BestLang != NULL) { + FreePool (BestLang); + BestLang = NULL; + } + if (!EFI_ERROR(Status)) { + return (RetVal); + } + } + Status = gBS->OpenProtocol( + TheHandle, + &gEfiComponentNameProtocolGuid, + (VOID**)&CompNameStruct, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (!EFI_ERROR(Status)) { + BestLang = GetBestLanguageForDriver (CompNameStruct->SupportedLanguages, Language, FALSE); + Status = CompNameStruct->GetDriverName(CompNameStruct, BestLang, &RetVal); + if (BestLang != NULL) { + FreePool (BestLang); + } + if (!EFI_ERROR(Status)) { + return (RetVal); + } + } + return (NULL); +} + +/** + Function to initialize the file global mHandleList object for use in + vonverting handles to index and index to handle. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +InternalShellInitHandleList( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN HandleCount; + HANDLE_LIST *ListWalker; + + if (mHandleList.NextIndex != 0) { + return EFI_SUCCESS; + } + InitializeListHead(&mHandleList.List.Link); + mHandleList.NextIndex = 1; + Status = gBS->LocateHandleBuffer ( + AllHandles, + NULL, + NULL, + &HandleCount, + &HandleBuffer + ); + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) { + return (Status); + } + for (mHandleList.NextIndex = 1 ; mHandleList.NextIndex <= HandleCount ; mHandleList.NextIndex++){ + ListWalker = AllocateZeroPool(sizeof(HANDLE_LIST)); + if (ListWalker != NULL) { + ListWalker->TheHandle = HandleBuffer[mHandleList.NextIndex - 1]; + ListWalker->TheIndex = mHandleList.NextIndex; + InsertTailList (&mHandleList.List.Link, &ListWalker->Link); + } + } + FreePool(HandleBuffer); + return (EFI_SUCCESS); +} + +/** + Function to retrieve the human-friendly index of a given handle. If the handle + does not have a index one will be automatically assigned. The index value is valid + until the termination of the shell application. + + @param[in] TheHandle The handle to retrieve an index for. + + @retval 0 A memory allocation failed. + @return The index of the handle. + +**/ +UINTN +EFIAPI +ConvertHandleToHandleIndex( + IN CONST EFI_HANDLE TheHandle + ) +{ + EFI_STATUS Status; + EFI_GUID **ProtocolBuffer; + UINTN ProtocolCount; + HANDLE_LIST *ListWalker; + + if (TheHandle == NULL) { + return 0; + } + + InternalShellInitHandleList(); + + for (ListWalker = (HANDLE_LIST*)GetFirstNode(&mHandleList.List.Link) + ; !IsNull(&mHandleList.List.Link,&ListWalker->Link) + ; ListWalker = (HANDLE_LIST*)GetNextNode(&mHandleList.List.Link,&ListWalker->Link) + ){ + if (ListWalker->TheHandle == TheHandle) { + // + // Verify that TheHandle is still present in the Handle Database + // + Status = gBS->ProtocolsPerHandle(TheHandle, &ProtocolBuffer, &ProtocolCount); + if (EFI_ERROR (Status)) { + // + // TheHandle is not present in the Handle Database, so delete from the handle list + // + RemoveEntryList (&ListWalker->Link); + return 0; + } + FreePool (ProtocolBuffer); + return (ListWalker->TheIndex); + } + } + + // + // Verify that TheHandle is valid handle + // + Status = gBS->ProtocolsPerHandle(TheHandle, &ProtocolBuffer, &ProtocolCount); + if (EFI_ERROR (Status)) { + // + // TheHandle is not valid, so do not add to handle list + // + return 0; + } + FreePool (ProtocolBuffer); + + ListWalker = AllocateZeroPool(sizeof(HANDLE_LIST)); + if (ListWalker == NULL) { + return 0; + } + ListWalker->TheHandle = TheHandle; + ListWalker->TheIndex = mHandleList.NextIndex++; + InsertTailList(&mHandleList.List.Link,&ListWalker->Link); + return (ListWalker->TheIndex); +} + + + +/** + Function to retrieve the EFI_HANDLE from the human-friendly index. + + @param[in] TheIndex The index to retrieve the EFI_HANDLE for. + + @retval NULL The index was invalid. + @return The EFI_HANDLE that index represents. + +**/ +EFI_HANDLE +EFIAPI +ConvertHandleIndexToHandle( + IN CONST UINTN TheIndex + ) +{ + EFI_STATUS Status; + EFI_GUID **ProtocolBuffer; + UINTN ProtocolCount; + HANDLE_LIST *ListWalker; + + InternalShellInitHandleList(); + + if (TheIndex >= mHandleList.NextIndex) { + return NULL; + } + + for (ListWalker = (HANDLE_LIST*)GetFirstNode(&mHandleList.List.Link) + ; !IsNull(&mHandleList.List.Link,&ListWalker->Link) + ; ListWalker = (HANDLE_LIST*)GetNextNode(&mHandleList.List.Link,&ListWalker->Link) + ){ + if (ListWalker->TheIndex == TheIndex && ListWalker->TheHandle != NULL) { + // + // Verify that LinkWalker->TheHandle is valid handle + // + Status = gBS->ProtocolsPerHandle(ListWalker->TheHandle, &ProtocolBuffer, &ProtocolCount); + if (!EFI_ERROR (Status)) { + FreePool (ProtocolBuffer); + } else { + // + // TheHandle is not valid, so do not add to handle list + // + ListWalker->TheHandle = NULL; + } + return (ListWalker->TheHandle); + } + } + return NULL; +} + +/** + Gets all the related EFI_HANDLEs based on the mask supplied. + + This function scans all EFI_HANDLES in the UEFI environment's handle database + and returns the ones with the specified relationship (Mask) to the specified + controller handle. + + If both DriverBindingHandle and ControllerHandle are NULL, then ASSERT. + If MatchingHandleCount is NULL, then ASSERT. + + If MatchingHandleBuffer is not NULL upon a successful return the memory must be + caller freed. + + @param[in] DriverBindingHandle The handle with Driver Binding protocol on it. + @param[in] ControllerHandle The handle with Device Path protocol on it. + @param[in] MatchingHandleCount The pointer to UINTN that specifies the number of HANDLES in + MatchingHandleBuffer. + @param[out] MatchingHandleBuffer On a successful return, a buffer of MatchingHandleCount + EFI_HANDLEs with a terminating NULL EFI_HANDLE. + @param[out] HandleType An array of type information. + + @retval EFI_SUCCESS The operation was successful, and any related handles + are in MatchingHandleBuffer. + @retval EFI_NOT_FOUND No matching handles were found. + @retval EFI_INVALID_PARAMETER A parameter was invalid or out of range. +**/ +EFI_STATUS +EFIAPI +ParseHandleDatabaseByRelationshipWithType ( + IN CONST EFI_HANDLE DriverBindingHandle OPTIONAL, + IN CONST EFI_HANDLE ControllerHandle OPTIONAL, + IN UINTN *HandleCount, + OUT EFI_HANDLE **HandleBuffer, + OUT UINTN **HandleType + ) +{ + EFI_STATUS Status; + UINTN HandleIndex; + EFI_GUID **ProtocolGuidArray; + UINTN ArrayCount; + UINTN ProtocolIndex; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo; + UINTN OpenInfoCount; + UINTN OpenInfoIndex; + UINTN ChildIndex; + INTN DriverBindingHandleIndex; + + ASSERT(HandleCount != NULL); + ASSERT(HandleBuffer != NULL); + ASSERT(HandleType != NULL); + ASSERT(DriverBindingHandle != NULL || ControllerHandle != NULL); + + *HandleCount = 0; + *HandleBuffer = NULL; + *HandleType = NULL; + + // + // Retrieve the list of all handles from the handle database + // + Status = gBS->LocateHandleBuffer ( + AllHandles, + NULL, + NULL, + HandleCount, + HandleBuffer + ); + if (EFI_ERROR (Status)) { + return (Status); + } + + *HandleType = AllocateZeroPool (*HandleCount * sizeof (UINTN)); + if (*HandleType == NULL) { + SHELL_FREE_NON_NULL (*HandleBuffer); + *HandleCount = 0; + return EFI_OUT_OF_RESOURCES; + } + + DriverBindingHandleIndex = -1; + for (HandleIndex = 0; HandleIndex < *HandleCount; HandleIndex++) { + if (DriverBindingHandle != NULL && (*HandleBuffer)[HandleIndex] == DriverBindingHandle) { + DriverBindingHandleIndex = (INTN)HandleIndex; + } + } + + for (HandleIndex = 0; HandleIndex < *HandleCount; HandleIndex++) { + // + // Retrieve the list of all the protocols on each handle + // + Status = gBS->ProtocolsPerHandle ( + (*HandleBuffer)[HandleIndex], + &ProtocolGuidArray, + &ArrayCount + ); + if (EFI_ERROR (Status)) { + continue; + } + + for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) { + + // + // Set the bit describing what this handle has + // + if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiLoadedImageProtocolGuid) ) { + (*HandleType)[HandleIndex] |= (UINTN)HR_IMAGE_HANDLE; + } else if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverBindingProtocolGuid) ) { + (*HandleType)[HandleIndex] |= (UINTN)HR_DRIVER_BINDING_HANDLE; + } else if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverConfiguration2ProtocolGuid)) { + (*HandleType)[HandleIndex] |= (UINTN)HR_DRIVER_CONFIGURATION_HANDLE; + } else if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverConfigurationProtocolGuid) ) { + (*HandleType)[HandleIndex] |= (UINTN)HR_DRIVER_CONFIGURATION_HANDLE; + } else if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverDiagnostics2ProtocolGuid) ) { + (*HandleType)[HandleIndex] |= (UINTN)HR_DRIVER_DIAGNOSTICS_HANDLE; + } else if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverDiagnosticsProtocolGuid) ) { + (*HandleType)[HandleIndex] |= (UINTN)HR_DRIVER_DIAGNOSTICS_HANDLE; + } else if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiComponentName2ProtocolGuid) ) { + (*HandleType)[HandleIndex] |= (UINTN)HR_COMPONENT_NAME_HANDLE; + } else if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiComponentNameProtocolGuid) ) { + (*HandleType)[HandleIndex] |= (UINTN)HR_COMPONENT_NAME_HANDLE; + } else if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDevicePathProtocolGuid) ) { + (*HandleType)[HandleIndex] |= (UINTN)HR_DEVICE_HANDLE; + } + // + // Retrieve the list of agents that have opened each protocol + // + Status = gBS->OpenProtocolInformation ( + (*HandleBuffer)[HandleIndex], + ProtocolGuidArray[ProtocolIndex], + &OpenInfo, + &OpenInfoCount + ); + if (EFI_ERROR (Status)) { + continue; + } + + if (ControllerHandle == NULL) { + // + // ControllerHandle == NULL and DriverBindingHandle != NULL. + // Return information on all the controller handles that the driver specified by DriverBindingHandle is managing + // + for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) { + if (OpenInfo[OpenInfoIndex].AgentHandle == DriverBindingHandle && (OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) { + (*HandleType)[HandleIndex] |= (UINTN)(HR_DEVICE_HANDLE | HR_CONTROLLER_HANDLE); + if (DriverBindingHandleIndex != -1) { + (*HandleType)[DriverBindingHandleIndex] |= (UINTN)HR_DEVICE_DRIVER; + } + } + if (OpenInfo[OpenInfoIndex].AgentHandle == DriverBindingHandle && (OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) { + (*HandleType)[HandleIndex] |= (UINTN)(HR_DEVICE_HANDLE | HR_CONTROLLER_HANDLE); + if (DriverBindingHandleIndex != -1) { + (*HandleType)[DriverBindingHandleIndex] |= (UINTN)(HR_BUS_DRIVER | HR_DEVICE_DRIVER); + } + for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) { + if (OpenInfo[OpenInfoIndex].ControllerHandle == (*HandleBuffer)[ChildIndex]) { + (*HandleType)[ChildIndex] |= (UINTN)(HR_DEVICE_HANDLE | HR_CHILD_HANDLE); + } + } + } + } + } + if (DriverBindingHandle == NULL && ControllerHandle != NULL) { + if (ControllerHandle == (*HandleBuffer)[HandleIndex]) { + (*HandleType)[HandleIndex] |= (UINTN)(HR_DEVICE_HANDLE | HR_CONTROLLER_HANDLE); + for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) { + if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) { + for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) { + if (OpenInfo[OpenInfoIndex].AgentHandle == (*HandleBuffer)[ChildIndex]) { + (*HandleType)[ChildIndex] |= (UINTN)HR_DEVICE_DRIVER; + } + } + } + if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) { + for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) { + if (OpenInfo[OpenInfoIndex].AgentHandle == (*HandleBuffer)[ChildIndex]) { + (*HandleType)[ChildIndex] |= (UINTN)(HR_BUS_DRIVER | HR_DEVICE_DRIVER); + } + if (OpenInfo[OpenInfoIndex].ControllerHandle == (*HandleBuffer)[ChildIndex]) { + (*HandleType)[ChildIndex] |= (UINTN)(HR_DEVICE_HANDLE | HR_CHILD_HANDLE); + } + } + } + } + } else { + for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) { + if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) { + if (OpenInfo[OpenInfoIndex].ControllerHandle == ControllerHandle) { + (*HandleType)[HandleIndex] |= (UINTN)(HR_DEVICE_HANDLE | HR_PARENT_HANDLE); + } + } + } + } + } + if (DriverBindingHandle != NULL && ControllerHandle != NULL) { + if (ControllerHandle == (*HandleBuffer)[HandleIndex]) { + (*HandleType)[HandleIndex] |= (UINTN)(HR_DEVICE_HANDLE | HR_CONTROLLER_HANDLE); + for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) { + if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) { + if (OpenInfo[OpenInfoIndex].AgentHandle == DriverBindingHandle) { + if (DriverBindingHandleIndex != -1) { + (*HandleType)[DriverBindingHandleIndex] |= (UINTN)HR_DEVICE_DRIVER; + } + } + } + if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) { + if (OpenInfo[OpenInfoIndex].AgentHandle == DriverBindingHandle) { + for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) { + if (OpenInfo[OpenInfoIndex].ControllerHandle == (*HandleBuffer)[ChildIndex]) { + (*HandleType)[ChildIndex] |= (UINTN)(HR_DEVICE_HANDLE | HR_CHILD_HANDLE); + } + } + } + + for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) { + if (OpenInfo[OpenInfoIndex].AgentHandle == (*HandleBuffer)[ChildIndex]) { + (*HandleType)[ChildIndex] |= (UINTN)(HR_BUS_DRIVER | HR_DEVICE_DRIVER); + } + } + } + } + } else { + for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) { + if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) { + if (OpenInfo[OpenInfoIndex].ControllerHandle == ControllerHandle) { + (*HandleType)[HandleIndex] |= (UINTN)(HR_DEVICE_HANDLE | HR_PARENT_HANDLE); + } + } + } + } + } + FreePool (OpenInfo); + } + FreePool (ProtocolGuidArray); + } + return EFI_SUCCESS; +} + +/** + Gets all the related EFI_HANDLEs based on the single EFI_HANDLE and the mask + supplied. + + This function will scan all EFI_HANDLES in the UEFI environment's handle database + and return all the ones with the specified relationship (Mask) to the specified + controller handle. + + If both DriverBindingHandle and ControllerHandle are NULL, then ASSERT. + If MatchingHandleCount is NULL, then ASSERT. + + If MatchingHandleBuffer is not NULL upon a sucessful return the memory must be + caller freed. + + @param[in] DriverBindingHandle Handle to a object with Driver Binding protocol + on it. + @param[in] ControllerHandle Handle to a device with Device Path protocol on it. + @param[in] Mask Mask of what relationship(s) is desired. + @param[in] MatchingHandleCount Poitner to UINTN specifying number of HANDLES in + MatchingHandleBuffer. + @param[out] MatchingHandleBuffer On a sucessful return a buffer of MatchingHandleCount + EFI_HANDLEs and a terminating NULL EFI_HANDLE. + + @retval EFI_SUCCESS The operation was sucessful and any related handles + are in MatchingHandleBuffer; + @retval EFI_NOT_FOUND No matching handles were found. + @retval EFI_INVALID_PARAMETER A parameter was invalid or out of range. +**/ +EFI_STATUS +EFIAPI +ParseHandleDatabaseByRelationship ( + IN CONST EFI_HANDLE DriverBindingHandle OPTIONAL, + IN CONST EFI_HANDLE ControllerHandle OPTIONAL, + IN CONST UINTN Mask, + IN UINTN *MatchingHandleCount, + OUT EFI_HANDLE **MatchingHandleBuffer OPTIONAL + ) +{ + EFI_STATUS Status; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN *HandleType; + UINTN HandleIndex; + + ASSERT(MatchingHandleCount != NULL); + ASSERT(DriverBindingHandle != NULL || ControllerHandle != NULL); + + if ((Mask & HR_VALID_MASK) != Mask) { + return (EFI_INVALID_PARAMETER); + } + + if ((Mask & HR_CHILD_HANDLE) != 0 && DriverBindingHandle == NULL) { + return (EFI_INVALID_PARAMETER); + } + + *MatchingHandleCount = 0; + if (MatchingHandleBuffer != NULL) { + *MatchingHandleBuffer = NULL; + } + + HandleBuffer = NULL; + HandleType = NULL; + + Status = ParseHandleDatabaseByRelationshipWithType ( + DriverBindingHandle, + ControllerHandle, + &HandleCount, + &HandleBuffer, + &HandleType + ); + if (!EFI_ERROR (Status)) { + // + // Count the number of handles that match the attributes in Mask + // + for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) { + if ((HandleType[HandleIndex] & Mask) == Mask) { + (*MatchingHandleCount)++; + } + } + // + // If no handles match the attributes in Mask then return EFI_NOT_FOUND + // + if (*MatchingHandleCount == 0) { + Status = EFI_NOT_FOUND; + } else { + + if (MatchingHandleBuffer == NULL) { + // + // Someone just wanted the count... + // + Status = EFI_SUCCESS; + } else { + // + // Allocate a handle buffer for the number of handles that matched the attributes in Mask + // + *MatchingHandleBuffer = AllocateZeroPool ((*MatchingHandleCount +1)* sizeof (EFI_HANDLE)); + if (*MatchingHandleBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + for (HandleIndex = 0, *MatchingHandleCount = 0 + ; HandleIndex < HandleCount + ; HandleIndex++ + ) { + // + // Fill the allocated buffer with the handles that matched the attributes in Mask + // + if ((HandleType[HandleIndex] & Mask) == Mask) { + (*MatchingHandleBuffer)[(*MatchingHandleCount)++] = HandleBuffer[HandleIndex]; + } + } + + // + // Make the last one NULL + // + (*MatchingHandleBuffer)[*MatchingHandleCount] = NULL; + + Status = EFI_SUCCESS; + } // *MatchingHandleBuffer == NULL (ELSE) + } // MacthingHandleBuffer == NULL (ELSE) + } // *MatchingHandleCount == 0 (ELSE) + } // no error on ParseHandleDatabaseByRelationshipWithType + + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + + if (HandleType != NULL) { + FreePool (HandleType); + } + + ASSERT ((MatchingHandleBuffer == NULL) || + (*MatchingHandleCount == 0 && *MatchingHandleBuffer == NULL) || + (*MatchingHandleCount != 0 && *MatchingHandleBuffer != NULL)); + return Status; +} + +/** + Gets handles for any child controllers of the passed in controller. + + @param[in] ControllerHandle The handle of the "parent controller" + @param[out] MatchingHandleCount Pointer to the number of handles in + MatchingHandleBuffer on return. + @param[out] MatchingHandleBuffer Buffer containing handles on a successful + return. + + + @retval EFI_SUCCESS The operation was sucessful. +**/ +EFI_STATUS +EFIAPI +ParseHandleDatabaseForChildControllers( + IN CONST EFI_HANDLE ControllerHandle, + OUT UINTN *MatchingHandleCount, + OUT EFI_HANDLE **MatchingHandleBuffer OPTIONAL + ) +{ + EFI_STATUS Status; + UINTN HandleIndex; + UINTN DriverBindingHandleCount; + EFI_HANDLE *DriverBindingHandleBuffer; + UINTN DriverBindingHandleIndex; + UINTN ChildControllerHandleCount; + EFI_HANDLE *ChildControllerHandleBuffer; + UINTN ChildControllerHandleIndex; + EFI_HANDLE *HandleBufferForReturn; + + if (MatchingHandleCount == NULL) { + return (EFI_INVALID_PARAMETER); + } + *MatchingHandleCount = 0; + + Status = PARSE_HANDLE_DATABASE_UEFI_DRIVERS ( + ControllerHandle, + &DriverBindingHandleCount, + &DriverBindingHandleBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get a buffer big enough for all the controllers. + // + HandleBufferForReturn = GetHandleListByProtocol(NULL); + if (HandleBufferForReturn == NULL) { + FreePool (DriverBindingHandleBuffer); + return (EFI_NOT_FOUND); + } + + for (DriverBindingHandleIndex = 0; DriverBindingHandleIndex < DriverBindingHandleCount; DriverBindingHandleIndex++) { + Status = PARSE_HANDLE_DATABASE_MANAGED_CHILDREN ( + DriverBindingHandleBuffer[DriverBindingHandleIndex], + ControllerHandle, + &ChildControllerHandleCount, + &ChildControllerHandleBuffer + ); + if (EFI_ERROR (Status)) { + continue; + } + + for (ChildControllerHandleIndex = 0; + ChildControllerHandleIndex < ChildControllerHandleCount; + ChildControllerHandleIndex++ + ) { + for (HandleIndex = 0; HandleIndex < *MatchingHandleCount; HandleIndex++) { + if (HandleBufferForReturn[HandleIndex] == ChildControllerHandleBuffer[ChildControllerHandleIndex]) { + break; + } + } + if (HandleIndex >= *MatchingHandleCount) { + HandleBufferForReturn[(*MatchingHandleCount)++] = ChildControllerHandleBuffer[ChildControllerHandleIndex]; + } + } + + FreePool (ChildControllerHandleBuffer); + } + + FreePool (DriverBindingHandleBuffer); + + if (MatchingHandleBuffer == NULL || *MatchingHandleCount == 0) { + // + // The caller is not interested in the actual handles, or we've found none. + // + FreePool (HandleBufferForReturn); + HandleBufferForReturn = NULL; + } + + if (MatchingHandleBuffer != NULL) { + *MatchingHandleBuffer = HandleBufferForReturn; + } + + ASSERT ((MatchingHandleBuffer == NULL) || + (*MatchingHandleCount == 0 && *MatchingHandleBuffer == NULL) || + (*MatchingHandleCount != 0 && *MatchingHandleBuffer != NULL)); + + return (EFI_SUCCESS); +} + +/** + Appends 1 buffer to another buffer. This will re-allocate the destination buffer + if necessary to fit all of the data. + + If DestinationBuffer is NULL, then ASSERT(). + + @param[in, out] DestinationBuffer The pointer to the pointer to the buffer to append onto. + @param[in, out] DestinationSize The pointer to the size of DestinationBuffer. + @param[in] SourceBuffer The pointer to the buffer to append onto DestinationBuffer. + @param[in] SourceSize The number of bytes of SourceBuffer to append. + + @retval NULL A memory allocation failed. + @retval NULL A parameter was invalid. + @return A pointer to (*DestinationBuffer). +**/ +VOID* +BuffernCatGrow ( + IN OUT VOID **DestinationBuffer, + IN OUT UINTN *DestinationSize, + IN VOID *SourceBuffer, + IN UINTN SourceSize + ) +{ + UINTN LocalDestinationSize; + UINTN LocalDestinationFinalSize; + + ASSERT(DestinationBuffer != NULL); + + if (SourceSize == 0 || SourceBuffer == NULL) { + return (*DestinationBuffer); + } + + if (DestinationSize == NULL) { + LocalDestinationSize = 0; + } else { + LocalDestinationSize = *DestinationSize; + } + + LocalDestinationFinalSize = LocalDestinationSize + SourceSize; + + if (DestinationSize != NULL) { + *DestinationSize = LocalDestinationSize; + } + + if (LocalDestinationSize == 0) { + // allcoate + *DestinationBuffer = AllocateZeroPool(LocalDestinationFinalSize); + } else { + // reallocate + *DestinationBuffer = ReallocatePool(LocalDestinationSize, LocalDestinationFinalSize, *DestinationBuffer); + } + + ASSERT(*DestinationBuffer != NULL); + + // copy + return (CopyMem(((UINT8*)(*DestinationBuffer)) + LocalDestinationSize, SourceBuffer, SourceSize)); +} + +/** + Gets handles for any child devices produced by the passed in driver. + + @param[in] DriverHandle The handle of the driver. + @param[in] MatchingHandleCount Pointer to the number of handles in + MatchingHandleBuffer on return. + @param[out] MatchingHandleBuffer Buffer containing handles on a successful + return. + @retval EFI_SUCCESS The operation was sucessful. + @sa ParseHandleDatabaseByRelationship +**/ +EFI_STATUS +EFIAPI +ParseHandleDatabaseForChildDevices( + IN CONST EFI_HANDLE DriverHandle, + IN UINTN *MatchingHandleCount, + OUT EFI_HANDLE **MatchingHandleBuffer OPTIONAL + ) +{ + EFI_HANDLE *Buffer; + EFI_HANDLE *Buffer2; + UINTN Count1; + UINTN Count2; + UINTN HandleIndex; + EFI_STATUS Status; + UINTN HandleBufferSize; + + ASSERT(MatchingHandleCount != NULL); + + HandleBufferSize = 0; + Buffer = NULL; + Buffer2 = NULL; + *MatchingHandleCount = 0; + + Status = PARSE_HANDLE_DATABASE_DEVICES ( + DriverHandle, + &Count1, + &Buffer + ); + if (!EFI_ERROR (Status)) { + for (HandleIndex = 0; HandleIndex < Count1; HandleIndex++) { + // + // now find the children + // + Status = PARSE_HANDLE_DATABASE_MANAGED_CHILDREN ( + DriverHandle, + Buffer[HandleIndex], + &Count2, + &Buffer2 + ); + if (EFI_ERROR(Status)) { + break; + } + // + // save out required and optional data elements + // + *MatchingHandleCount += Count2; + if (MatchingHandleBuffer != NULL) { + *MatchingHandleBuffer = BuffernCatGrow((VOID**)MatchingHandleBuffer, &HandleBufferSize, Buffer2, Count2 * sizeof(Buffer2[0])); + } + + // + // free the memory + // + if (Buffer2 != NULL) { + FreePool(Buffer2); + } + } + } + + if (Buffer != NULL) { + FreePool(Buffer); + } + return (Status); +} + +/** + Function to get all handles that support a given protocol or all handles. + + @param[in] ProtocolGuid The guid of the protocol to get handles for. If NULL + then the function will return all handles. + + @retval NULL A memory allocation failed. + @return A NULL terminated list of handles. +**/ +EFI_HANDLE* +EFIAPI +GetHandleListByProtocol ( + IN CONST EFI_GUID *ProtocolGuid OPTIONAL + ) +{ + EFI_HANDLE *HandleList; + UINTN Size; + EFI_STATUS Status; + + Size = 0; + HandleList = NULL; + + // + // We cannot use LocateHandleBuffer since we need that NULL item on the ends of the list! + // + if (ProtocolGuid == NULL) { + Status = gBS->LocateHandle(AllHandles, NULL, NULL, &Size, HandleList); + if (Status == EFI_BUFFER_TOO_SMALL) { + HandleList = AllocateZeroPool(Size + sizeof(EFI_HANDLE)); + if (HandleList == NULL) { + return (NULL); + } + Status = gBS->LocateHandle(AllHandles, NULL, NULL, &Size, HandleList); + HandleList[Size/sizeof(EFI_HANDLE)] = NULL; + } + } else { + Status = gBS->LocateHandle(ByProtocol, (EFI_GUID*)ProtocolGuid, NULL, &Size, HandleList); + if (Status == EFI_BUFFER_TOO_SMALL) { + HandleList = AllocateZeroPool(Size + sizeof(EFI_HANDLE)); + if (HandleList == NULL) { + return (NULL); + } + Status = gBS->LocateHandle(ByProtocol, (EFI_GUID*)ProtocolGuid, NULL, &Size, HandleList); + HandleList[Size/sizeof(EFI_HANDLE)] = NULL; + } + } + if (EFI_ERROR(Status)) { + if (HandleList != NULL) { + FreePool(HandleList); + } + return (NULL); + } + return (HandleList); +} + +/** + Function to get all handles that support some protocols. + + @param[in] ProtocolGuids A NULL terminated list of protocol GUIDs. + + @retval NULL A memory allocation failed. + @retval NULL ProtocolGuids was NULL. + @return A NULL terminated list of EFI_HANDLEs. +**/ +EFI_HANDLE* +EFIAPI +GetHandleListByProtocolList ( + IN CONST EFI_GUID **ProtocolGuids + ) +{ + EFI_HANDLE *HandleList; + UINTN Size; + UINTN TotalSize; + UINTN TempSize; + EFI_STATUS Status; + CONST EFI_GUID **GuidWalker; + EFI_HANDLE *HandleWalker1; + EFI_HANDLE *HandleWalker2; + + Size = 0; + HandleList = NULL; + TotalSize = sizeof(EFI_HANDLE); + + for (GuidWalker = ProtocolGuids ; GuidWalker != NULL && *GuidWalker != NULL ; GuidWalker++,Size = 0){ + Status = gBS->LocateHandle(ByProtocol, (EFI_GUID*)(*GuidWalker), NULL, &Size, NULL); + if (Status == EFI_BUFFER_TOO_SMALL) { + TotalSize += Size; + } + } + + // + // No handles were found... + // + if (TotalSize == sizeof(EFI_HANDLE)) { + return (NULL); + } + + HandleList = AllocateZeroPool(TotalSize); + if (HandleList == NULL) { + return (NULL); + } + + Size = 0; + for (GuidWalker = ProtocolGuids ; GuidWalker != NULL && *GuidWalker != NULL ; GuidWalker++){ + TempSize = TotalSize - Size; + Status = gBS->LocateHandle(ByProtocol, (EFI_GUID*)(*GuidWalker), NULL, &TempSize, HandleList+(Size/sizeof(EFI_HANDLE))); + + // + // Allow for missing protocols... Only update the 'used' size upon success. + // + if (!EFI_ERROR(Status)) { + Size += TempSize; + } + } + ASSERT(HandleList[(TotalSize/sizeof(EFI_HANDLE))-1] == NULL); + + for (HandleWalker1 = HandleList ; HandleWalker1 != NULL && *HandleWalker1 != NULL ; HandleWalker1++) { + for (HandleWalker2 = HandleWalker1 + 1; HandleWalker2 != NULL && *HandleWalker2 != NULL ; HandleWalker2++) { + if (*HandleWalker1 == *HandleWalker2) { + // + // copy memory back 1 handle width. + // + CopyMem(HandleWalker2, HandleWalker2 + 1, TotalSize - ((HandleWalker2-HandleList+1)*sizeof(EFI_HANDLE))); + } + } + } + + return (HandleList); +} + +/** + Return all supported GUIDs. + + @param[out] Guids The buffer to return all supported GUIDs. + @param[in, out] Count On input, the count of GUIDs the buffer can hold, + On output, the count of GUIDs to return. + + @retval EFI_INVALID_PARAMETER Count is NULL. + @retval EFI_BUFFER_TOO_SMALL Buffer is not enough to hold all GUIDs. + @retval EFI_SUCCESS GUIDs are returned successfully. +**/ +EFI_STATUS +EFIAPI +GetAllMappingGuids ( + OUT EFI_GUID *Guids, + IN OUT UINTN *Count + ) +{ + UINTN GuidCount; + UINTN NtGuidCount; + UINTN Index; + + if (Count == NULL) { + return EFI_INVALID_PARAMETER; + } + + NtGuidCount = 0; + if (PcdGetBool (PcdShellIncludeNtGuids)) { + NtGuidCount = ARRAY_SIZE (mGuidStringListNT) - 1; + } + GuidCount = ARRAY_SIZE (mGuidStringList) - 1; + + if (*Count < NtGuidCount + GuidCount + mGuidListCount) { + *Count = NtGuidCount + GuidCount + mGuidListCount; + return EFI_BUFFER_TOO_SMALL; + } + + for (Index = 0; Index < NtGuidCount; Index++) { + CopyGuid (&Guids[Index], mGuidStringListNT[Index].GuidId); + } + + for (Index = 0; Index < GuidCount; Index++) { + CopyGuid (&Guids[NtGuidCount + Index], mGuidStringList[Index].GuidId); + } + + for (Index = 0; Index < mGuidListCount; Index++) { + CopyGuid (&Guids[NtGuidCount + GuidCount + Index], mGuidList[Index].GuidId); + } + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.h new file mode 100644 index 00000000..3ddba6a2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.h @@ -0,0 +1,294 @@ +/** @file + Provides interface to advanced shell functionality for parsing both handle and protocol database. + + Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+ (C) Copyright 2013-2016 Hewlett-Packard Development Company, L.P.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _UEFI_HANDLE_PARSING_LIB_INTERNAL_H_ +#define _UEFI_HANDLE_PARSING_LIB_INTERNAL_H_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION_V1 1 +#define EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION_V2 2 + +/// +/// EFI_FIRMWARE_IMAGE_DESCRIPTOR in UEFI spec < 2.4a +/// +typedef struct { + /// + /// A unique number identifying the firmware image within the device. The number is + /// between 1 and DescriptorCount. + /// + UINT8 ImageIndex; + /// + /// A unique number identifying the firmware image type. + /// + EFI_GUID ImageTypeId; + /// + /// A unique number identifying the firmware image. + /// + UINT64 ImageId; + /// + /// A pointer to a null-terminated string representing the firmware image name. + /// + CHAR16 *ImageIdName; + /// + /// Identifies the version of the device firmware. The format is vendor specific and new + /// version must have a greater value than an old version. + /// + UINT32 Version; + /// + /// A pointer to a null-terminated string representing the firmware image version name. + /// + CHAR16 *VersionName; + /// + /// Size of the image in bytes. If size=0, then only ImageIndex and ImageTypeId are valid. + /// + UINTN Size; + /// + /// Image attributes that are supported by this device. See 'Image Attribute Definitions' + /// for possible returned values of this parameter. A value of 1 indicates the attribute is + /// supported and the current setting value is indicated in AttributesSetting. A + /// value of 0 indicates the attribute is not supported and the current setting value in + /// AttributesSetting is meaningless. + /// + UINT64 AttributesSupported; + /// + /// Image attributes. See 'Image Attribute Definitions' for possible returned values of + /// this parameter. + /// + UINT64 AttributesSetting; + /// + /// Image compatibilities. See 'Image Compatibility Definitions' for possible returned + /// values of this parameter. + /// + UINT64 Compatibilities; +} EFI_FIRMWARE_IMAGE_DESCRIPTOR_V1; + + +/// +/// EFI_FIRMWARE_IMAGE_DESCRIPTOR in UEFI spec > 2.4a and < 2.5 +/// +typedef struct { + /// + /// A unique number identifying the firmware image within the device. The number is + /// between 1 and DescriptorCount. + /// + UINT8 ImageIndex; + /// + /// A unique number identifying the firmware image type. + /// + EFI_GUID ImageTypeId; + /// + /// A unique number identifying the firmware image. + /// + UINT64 ImageId; + /// + /// A pointer to a null-terminated string representing the firmware image name. + /// + CHAR16 *ImageIdName; + /// + /// Identifies the version of the device firmware. The format is vendor specific and new + /// version must have a greater value than an old version. + /// + UINT32 Version; + /// + /// A pointer to a null-terminated string representing the firmware image version name. + /// + CHAR16 *VersionName; + /// + /// Size of the image in bytes. If size=0, then only ImageIndex and ImageTypeId are valid. + /// + UINTN Size; + /// + /// Image attributes that are supported by this device. See 'Image Attribute Definitions' + /// for possible returned values of this parameter. A value of 1 indicates the attribute is + /// supported and the current setting value is indicated in AttributesSetting. A + /// value of 0 indicates the attribute is not supported and the current setting value in + /// AttributesSetting is meaningless. + /// + UINT64 AttributesSupported; + /// + /// Image attributes. See 'Image Attribute Definitions' for possible returned values of + /// this parameter. + /// + UINT64 AttributesSetting; + /// + /// Image compatibilities. See 'Image Compatibility Definitions' for possible returned + /// values of this parameter. + /// + UINT64 Compatibilities; + /// + /// Describes the lowest ImageDescriptor version that the device will accept. Only + /// present in version 2 or higher. + UINT32 LowestSupportedImageVersion; +} EFI_FIRMWARE_IMAGE_DESCRIPTOR_V2; + +typedef struct { + LIST_ENTRY Link; + EFI_HANDLE TheHandle; + UINTN TheIndex; +}HANDLE_LIST; + +typedef struct { + HANDLE_LIST List; + UINTN NextIndex; +} HANDLE_INDEX_LIST; + +typedef +CHAR16 * +(EFIAPI *DUMP_PROTOCOL_INFO)( + IN CONST EFI_HANDLE TheHandle, + IN CONST BOOLEAN Verbose + ); + +typedef struct _GUID_INFO_BLOCK{ + EFI_STRING_ID StringId; + EFI_GUID *GuidId; + DUMP_PROTOCOL_INFO DumpInfo; +} GUID_INFO_BLOCK; + +#endif + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf new file mode 100644 index 00000000..868e6484 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf @@ -0,0 +1,336 @@ +## @file +# Provides interface to advanced shell functionality for parsing both handle and protocol database. +# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+# (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
+# (C) Copyright 2015-2021 Hewlett Packard Enterprise Development LP
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiHandleParsingLib + FILE_GUID = 3CDC7177-CC2A-4678-BA8F-1A936A093FA4 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = HandleParsingLib|UEFI_APPLICATION UEFI_DRIVER DXE_RUNTIME_DRIVER + CONSTRUCTOR = HandleParsingLibConstructor + DESTRUCTOR = HandleParsingLibDestructor + +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources.common] + UefiHandleParsingLib.c + UefiHandleParsingLib.h + UefiHandleParsingLib.uni + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + ShellPkg/ShellPkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + MemoryAllocationLib + DevicePathLib + BaseLib + BaseMemoryLib + DebugLib + FileHandleLib + PrintLib + UefiLib + HiiLib + SortLib + PeCoffGetEntryPointLib + +[Protocols] + gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES + + # shell 2.0 + gEfiShellProtocolGuid ## SOMETIMES_CONSUMES + gEfiShellParametersProtocolGuid ## SOMETIMES_CONSUMES + + # 'old' shell + gEfiShellEnvironment2Guid ## SOMETIMES_CONSUMES + gEfiShellInterfaceGuid ## SOMETIMES_CONSUMES + + gEfiUnicodeCollation2ProtocolGuid ## UNDEFINED + gEfiDevicePathToTextProtocolGuid ## UNDEFINED + gEfiBusSpecificDriverOverrideProtocolGuid ## UNDEFINED + gEfiDevicePathUtilitiesProtocolGuid ## UNDEFINED + gEfiDevicePathFromTextProtocolGuid ## UNDEFINED + gEfiPlatformDriverOverrideProtocolGuid ## UNDEFINED + gEfiSimpleTextInProtocolGuid ## UNDEFINED + gEfiPlatformToDriverConfigurationProtocolGuid ## UNDEFINED + gEfiDriverSupportedEfiVersionProtocolGuid ## UNDEFINED + gEfiLoadedImageProtocolGuid ## CONSUMES + gEfiDevicePathProtocolGuid ## CONSUMES + gEfiLoadedImageDevicePathProtocolGuid ## UNDEFINED + gEfiSimpleTextOutProtocolGuid ## UNDEFINED + gEfiSimplePointerProtocolGuid ## UNDEFINED + gEfiAbsolutePointerProtocolGuid ## UNDEFINED + gEfiSerialIoProtocolGuid ## UNDEFINED + gEfiEdidDiscoveredProtocolGuid ## UNDEFINED + gEfiEdidActiveProtocolGuid ## UNDEFINED + gEfiEdidOverrideProtocolGuid ## UNDEFINED + gEfiLoadFileProtocolGuid ## UNDEFINED + gEfiLoadFile2ProtocolGuid ## UNDEFINED + gEfiTapeIoProtocolGuid ## UNDEFINED + gEfiDiskIoProtocolGuid ## UNDEFINED + gEfiBlockIoProtocolGuid ## UNDEFINED + gEfiUnicodeCollationProtocolGuid ## UNDEFINED + gEfiPciRootBridgeIoProtocolGuid ## UNDEFINED + gEfiPciIoProtocolGuid ## UNDEFINED + gEfiScsiPassThruProtocolGuid ## UNDEFINED + gEfiScsiIoProtocolGuid ## UNDEFINED + gEfiExtScsiPassThruProtocolGuid ## UNDEFINED + gEfiIScsiInitiatorNameProtocolGuid ## UNDEFINED + gEfiUsbIoProtocolGuid ## UNDEFINED + gEfiUsbHcProtocolGuid ## UNDEFINED + gEfiUsb2HcProtocolGuid ## UNDEFINED + gEfiDebugSupportProtocolGuid ## UNDEFINED + gEfiDebugPortProtocolGuid ## UNDEFINED + gEfiDecompressProtocolGuid ## UNDEFINED + gEfiAcpiTableProtocolGuid ## UNDEFINED + gEfiEbcProtocolGuid ## UNDEFINED + gEfiSimpleNetworkProtocolGuid ## UNDEFINED + gEfiNetworkInterfaceIdentifierProtocolGuid ## UNDEFINED + gEfiNetworkInterfaceIdentifierProtocolGuid_31 ## UNDEFINED + gEfiPxeBaseCodeProtocolGuid ## UNDEFINED + gEfiPxeBaseCodeCallbackProtocolGuid ## UNDEFINED + gEfiBisProtocolGuid ## UNDEFINED + gEfiManagedNetworkServiceBindingProtocolGuid ## UNDEFINED + gEfiManagedNetworkProtocolGuid ## UNDEFINED + gEfiArpServiceBindingProtocolGuid ## UNDEFINED + gEfiArpProtocolGuid ## UNDEFINED + gEfiDhcp4ServiceBindingProtocolGuid ## UNDEFINED + gEfiDhcp4ProtocolGuid ## UNDEFINED + gEfiTcp4ServiceBindingProtocolGuid ## UNDEFINED + gEfiTcp4ProtocolGuid ## UNDEFINED + gEfiIp4ServiceBindingProtocolGuid ## UNDEFINED + gEfiIp4ProtocolGuid ## UNDEFINED + gEfiIp4ConfigProtocolGuid ## UNDEFINED + gEfiIp4Config2ProtocolGuid ## UNDEFINED + gEfiUdp4ServiceBindingProtocolGuid ## UNDEFINED + gEfiUdp4ProtocolGuid ## UNDEFINED + gEfiMtftp4ServiceBindingProtocolGuid ## UNDEFINED + gEfiMtftp4ProtocolGuid ## UNDEFINED + gEfiAuthenticationInfoProtocolGuid ## UNDEFINED + gEfiHashServiceBindingProtocolGuid ## UNDEFINED + gEfiHashProtocolGuid ## UNDEFINED + gEfiHiiFontProtocolGuid ## UNDEFINED + gEfiHiiStringProtocolGuid ## UNDEFINED + gEfiHiiImageProtocolGuid ## UNDEFINED + gEfiHiiConfigRoutingProtocolGuid ## UNDEFINED + gEfiHiiConfigAccessProtocolGuid ## UNDEFINED + gEfiFormBrowser2ProtocolGuid ## UNDEFINED + gEfiDeviceIoProtocolGuid ## UNDEFINED + gEfiUgaDrawProtocolGuid ## UNDEFINED + gEfiUgaIoProtocolGuid ## UNDEFINED + gEfiDriverConfigurationProtocolGuid ## UNDEFINED + gEfiDriverConfiguration2ProtocolGuid ## UNDEFINED + gEfiSimpleTextInputExProtocolGuid ## UNDEFINED + gEfiIp6ServiceBindingProtocolGuid ## UNDEFINED + gEfiIp6ProtocolGuid ## UNDEFINED + gEfiIp6ConfigProtocolGuid ## UNDEFINED + gEfiMtftp6ServiceBindingProtocolGuid ## UNDEFINED + gEfiMtftp6ProtocolGuid ## UNDEFINED + gEfiDhcp6ServiceBindingProtocolGuid ## UNDEFINED + gEfiDhcp6ProtocolGuid ## UNDEFINED + gEfiUdp6ServiceBindingProtocolGuid ## UNDEFINED + gEfiUdp6ProtocolGuid ## UNDEFINED + gEfiTcp6ServiceBindingProtocolGuid ## UNDEFINED + gEfiTcp6ProtocolGuid ## UNDEFINED + gEfiVlanConfigProtocolGuid ## UNDEFINED + gEfiEapProtocolGuid ## UNDEFINED + gEfiEapManagementProtocolGuid ## UNDEFINED + gEfiFtp4ServiceBindingProtocolGuid ## UNDEFINED + gEfiFtp4ProtocolGuid ## UNDEFINED + gEfiIpSecConfigProtocolGuid ## UNDEFINED + gEfiDriverHealthProtocolGuid ## UNDEFINED + gEfiDeferredImageLoadProtocolGuid ## UNDEFINED + gEfiUserCredentialProtocolGuid ## UNDEFINED + gEfiUserManagerProtocolGuid ## UNDEFINED + gEfiAtaPassThruProtocolGuid ## UNDEFINED + gEfiFirmwareManagementProtocolGuid ## UNDEFINED + gEfiIpSecProtocolGuid ## UNDEFINED + gEfiIpSec2ProtocolGuid ## UNDEFINED + gEfiKmsProtocolGuid ## UNDEFINED + gEfiBlockIo2ProtocolGuid ## UNDEFINED + gEfiStorageSecurityCommandProtocolGuid ## UNDEFINED + gEfiUserCredential2ProtocolGuid ## UNDEFINED + gPcdProtocolGuid ## UNDEFINED + gEfiTcgProtocolGuid ## UNDEFINED + gEfiHiiPackageListProtocolGuid ## UNDEFINED + gEfiDriverFamilyOverrideProtocolGuid ## UNDEFINED + gEfiIdeControllerInitProtocolGuid ## UNDEFINED + gEfiDiskIo2ProtocolGuid ## UNDEFINED + gEfiAdapterInformationProtocolGuid ## UNDEFINED + gEfiShellDynamicCommandProtocolGuid ## UNDEFINED + gEfiDiskInfoProtocolGuid ## UNDEFINED + gGetPcdInfoProtocolGuid ## UNDEFINED + gEfiBdsArchProtocolGuid ## UNDEFINED + gEfiCpuArchProtocolGuid ## UNDEFINED + gEfiMetronomeArchProtocolGuid ## UNDEFINED + gEfiMonotonicCounterArchProtocolGuid ## UNDEFINED + gEfiRealTimeClockArchProtocolGuid ## UNDEFINED + gEfiResetArchProtocolGuid ## UNDEFINED + gEfiRuntimeArchProtocolGuid ## UNDEFINED + gEfiSecurityArchProtocolGuid ## UNDEFINED + gEfiTimerArchProtocolGuid ## UNDEFINED + gEfiVariableWriteArchProtocolGuid ## UNDEFINED + gEfiVariableArchProtocolGuid ## UNDEFINED + gEfiSecurityPolicyProtocolGuid ## UNDEFINED + gEfiWatchdogTimerArchProtocolGuid ## UNDEFINED + gEfiStatusCodeRuntimeProtocolGuid ## UNDEFINED + gEfiSmbusHcProtocolGuid ## UNDEFINED + gEfiFirmwareVolume2ProtocolGuid ## UNDEFINED + gEfiFirmwareVolumeBlockProtocolGuid ## UNDEFINED + gEfiCapsuleArchProtocolGuid ## UNDEFINED + gEfiMpServiceProtocolGuid ## UNDEFINED + gEfiPciHostBridgeResourceAllocationProtocolGuid ## UNDEFINED + gEfiPciPlatformProtocolGuid ## UNDEFINED + gEfiPciOverrideProtocolGuid ## UNDEFINED + gEfiPciEnumerationCompleteProtocolGuid ## UNDEFINED + gEfiIncompatiblePciDeviceSupportProtocolGuid ## UNDEFINED + gEfiPciHotPlugInitProtocolGuid ## UNDEFINED + gEfiPciHotPlugRequestProtocolGuid ## UNDEFINED + gEfiSmbiosProtocolGuid ## UNDEFINED + gEfiS3SaveStateProtocolGuid ## UNDEFINED + gEfiS3SmmSaveStateProtocolGuid ## UNDEFINED + gEfiRscHandlerProtocolGuid ## UNDEFINED + gEfiSmmRscHandlerProtocolGuid ## UNDEFINED + gEfiAcpiSdtProtocolGuid ## UNDEFINED + gEfiSioProtocolGuid ## UNDEFINED + gEfiSmmCpuIo2ProtocolGuid ## UNDEFINED + gEfiSmmBase2ProtocolGuid ## UNDEFINED + gEfiSmmAccess2ProtocolGuid ## UNDEFINED + gEfiSmmControl2ProtocolGuid ## UNDEFINED + gEfiSmmConfigurationProtocolGuid ## UNDEFINED + gEfiSmmReadyToLockProtocolGuid ## UNDEFINED + gEfiDxeSmmReadyToLockProtocolGuid ## UNDEFINED + gEfiSmmCommunicationProtocolGuid ## UNDEFINED + gEfiSmmStatusCodeProtocolGuid ## UNDEFINED + gEfiSmmCpuProtocolGuid ## UNDEFINED + gEfiSmmPciRootBridgeIoProtocolGuid ## UNDEFINED + gEfiSmmSwDispatch2ProtocolGuid ## UNDEFINED + gEfiSmmSxDispatch2ProtocolGuid ## UNDEFINED + gEfiSmmPeriodicTimerDispatch2ProtocolGuid ## UNDEFINED + gEfiSmmUsbDispatch2ProtocolGuid ## UNDEFINED + gEfiSmmGpiDispatch2ProtocolGuid ## UNDEFINED + gEfiSmmStandbyButtonDispatch2ProtocolGuid ## UNDEFINED + gEfiSmmPowerButtonDispatch2ProtocolGuid ## UNDEFINED + gEfiSmmIoTrapDispatch2ProtocolGuid ## UNDEFINED + gEfiPcdProtocolGuid ## UNDEFINED + gEfiFirmwareVolumeBlock2ProtocolGuid ## UNDEFINED + gEfiCpuIo2ProtocolGuid ## UNDEFINED + gEfiLegacyRegion2ProtocolGuid ## UNDEFINED + gEfiSecurity2ArchProtocolGuid ## UNDEFINED + gEfiSmmEndOfDxeProtocolGuid ## UNDEFINED + gEfiIsaHcProtocolGuid ## UNDEFINED + gEfiIsaHcServiceBindingProtocolGuid ## UNDEFINED + gEfiSioControlProtocolGuid ## UNDEFINED + gEfiGetPcdInfoProtocolGuid ## UNDEFINED + gEfiI2cMasterProtocolGuid ## UNDEFINED + gEfiI2cIoProtocolGuid ## UNDEFINED + gEfiI2cEnumerateProtocolGuid ## UNDEFINED + gEfiI2cHostProtocolGuid ## UNDEFINED + gEfiI2cBusConfigurationManagementProtocolGuid ## UNDEFINED + gEfiTcg2ProtocolGuid ## UNDEFINED + gEfiTimestampProtocolGuid ## UNDEFINED + gEfiRngProtocolGuid ## UNDEFINED + gEfiNvmExpressPassThruProtocolGuid ## UNDEFINED + gEfiHash2ServiceBindingProtocolGuid ## UNDEFINED + gEfiHash2ProtocolGuid ## UNDEFINED + gEfiBlockIoCryptoProtocolGuid ## UNDEFINED + gEfiSmartCardReaderProtocolGuid ## UNDEFINED + gEfiSmartCardEdgeProtocolGuid ## UNDEFINED + gEfiUsbFunctionIoProtocolGuid ## UNDEFINED + gEfiBluetoothHcProtocolGuid ## UNDEFINED + gEfiBluetoothIoServiceBindingProtocolGuid ## UNDEFINED + gEfiBluetoothIoProtocolGuid ## UNDEFINED + gEfiBluetoothConfigProtocolGuid ## UNDEFINED + gEfiRegularExpressionProtocolGuid ## UNDEFINED + gEfiBootManagerPolicyProtocolGuid ## UNDEFINED + gEfiConfigKeywordHandlerProtocolGuid ## UNDEFINED + gEfiWiFiProtocolGuid ## UNDEFINED + gEfiEapManagement2ProtocolGuid ## UNDEFINED + gEfiEapConfigurationProtocolGuid ## UNDEFINED + gEfiPkcs7VerifyProtocolGuid ## UNDEFINED + gEfiDns4ServiceBindingProtocolGuid ## UNDEFINED + gEfiDns4ProtocolGuid ## UNDEFINED + gEfiDns6ServiceBindingProtocolGuid ## UNDEFINED + gEfiDns6ProtocolGuid ## UNDEFINED + gEfiHttpServiceBindingProtocolGuid ## UNDEFINED + gEfiHttpProtocolGuid ## UNDEFINED + gEfiHttpUtilitiesProtocolGuid ## UNDEFINED + gEfiRestProtocolGuid ## UNDEFINED + gEfiRestExProtocolGuid ## UNDEFINED + gEfiRedfishDiscoverProtocolGuid ## UNDEFINED + gEfiMmEndOfDxeProtocolGuid ## UNDEFINED + gEfiMmIoTrapDispatchProtocolGuid ## UNDEFINED + gEfiMmPowerButtonDispatchProtocolGuid ## UNDEFINED + gEfiMmStandbyButtonDispatchProtocolGuid ## UNDEFINED + gEfiMmGpiDispatchProtocolGuid ## UNDEFINED + gEfiMmUsbDispatchProtocolGuid ## UNDEFINED + gEfiMmPeriodicTimerDispatchProtocolGuid ## UNDEFINED + gEfiMmSxDispatchProtocolGuid ## UNDEFINED + gEfiMmSwDispatchProtocolGuid ## UNDEFINED + gEfiMmPciRootBridgeIoProtocolGuid ## UNDEFINED + gEfiMmCpuProtocolGuid ## UNDEFINED + gEfiMmStatusCodeProtocolGuid ## UNDEFINED + gEfiDxeMmReadyToLockProtocolGuid ## UNDEFINED + gEfiMmConfigurationProtocolGuid ## UNDEFINED + gEfiMmReadyToLockProtocolGuid ## UNDEFINED + gEfiMmControlProtocolGuid ## UNDEFINED + gEfiMmAccessProtocolGuid ## UNDEFINED + gEfiMmBaseProtocolGuid ## UNDEFINED + gEfiMmCpuIoProtocolGuid ## UNDEFINED + gEfiMmRscHandlerProtocolGuid ## UNDEFINED + gEfiMmCommunicationProtocolGuid ## UNDEFINED + gEfiTlsServiceBindingProtocolGuid ## UNDEFINED + gEfiTlsProtocolGuid ## UNDEFINED + gEfiTlsConfigurationProtocolGuid ## UNDEFINED + gEfiSupplicantServiceBindingProtocolGuid ## UNDEFINED + gEfiSupplicantProtocolGuid ## UNDEFINED + gEfiWiFi2ProtocolGuid ## UNDEFINED + gEfiRamDiskProtocolGuid ## UNDEFINED + gEfiHiiImageDecoderProtocolGuid ## UNDEFINED + gEfiHiiImageExProtocolGuid ## UNDEFINED + gEfiSdMmcPassThruProtocolGuid ## UNDEFINED + gEfiEraseBlockProtocolGuid ## UNDEFINED + gEfiBluetoothAttributeProtocolGuid ## UNDEFINED + gEfiBluetoothAttributeServiceBindingProtocolGuid ## UNDEFINED + gEfiBluetoothLeConfigProtocolGuid ## UNDEFINED + gEfiUfsDeviceConfigProtocolGuid ## UNDEFINED + gEfiHttpBootCallbackProtocolGuid ## UNDEFINED + gEfiResetNotificationProtocolGuid ## UNDEFINED + gEfiPartitionInfoProtocolGuid ## UNDEFINED + gEfiHiiPopupProtocolGuid ## UNDEFINED + +[Guids] + gEfiFileInfoGuid ## UNDEFINED + gEfiShellEnvironment2ExtGuid ## SOMETIMES_CONSUMES ## GUID + gEfiPcAnsiGuid ## UNDEFINED + gEfiVT100Guid ## UNDEFINED + gEfiVT100PlusGuid ## UNDEFINED + gEfiVTUTF8Guid ## UNDEFINED + gEfiStandardErrorDeviceGuid ## UNDEFINED + gEfiConsoleInDeviceGuid ## UNDEFINED + gEfiConsoleOutDeviceGuid ## UNDEFINED + gEfiFileSystemInfoGuid ## UNDEFINED + gEfiGlobalVariableGuid ## UNDEFINED + gEfiPartTypeSystemPartGuid ## UNDEFINED + gEfiPartTypeLegacyMbrGuid ## UNDEFINED + gHandleParsingHiiGuid ## UNDEFINED + gEfiAdapterInfoMediaStateGuid ## SOMETIMES_CONSUMES ## GUID + gEfiAdapterInfoNetworkBootGuid ## SOMETIMES_CONSUMES ## GUID + gEfiAdapterInfoSanMacAddressGuid ## SOMETIMES_CONSUMES ## GUID + gEfiAdapterInfoUndiIpv6SupportGuid ## SOMETIMES_CONSUMES ## GUID + +[Pcd.common] + gEfiShellPkgTokenSpaceGuid.PcdShellIncludeNtGuids ## CONSUMES diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.uni b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.uni new file mode 100644 index 00000000..aa3396ce --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.uni @@ -0,0 +1,508 @@ +// /** +// +// Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.
+// (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
+// (C) Copyright 2015-2021 Hewlett Packard Enterprise Development LP
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// Module Name: +// +// UefiHandleParsingLib.uni +// +// Abstract: +// +// +// +// **/ + +/=# + +#langdef en-US "english" + +// +// Protocol names used making the GUID <-> Name bi-directional list +// + +// basics Images & Device Path +#string STR_LOADED_IMAGE #language en-US "LoadedImage" +#string STR_DEVICE_PATH #language en-US "DevicePath" +#string STR_IMAGE_PATH #language en-US "ImageDevicePath" +#string STR_DEVICE_PATH_UTIL #language en-US "DevicePathUtilities" +#string STR_DEVICE_PATH_TXT #language en-US "DevicePathToText" +#string STR_DEVICE_PATH_FTXT #language en-US "DevicePathFromText" +#string STR_DEVICE_PATH_PC #language en-US "DevicePathPCAnsi" +#string STR_DEVICE_PATH_VT100 #language en-US "DevicePathVT100" +#string STR_DEVICE_PATH_VT100P #language en-US "DevicePathVT100+" +#string STR_DEVICE_PATH_VTUTF8 #language en-US "DevicePathVTUTF8" + +// Drivers +#string STR_DRIVER_BINDING #language en-US "DriverBinding" +#string STR_PLATFORM_OVERRIDE #language en-US "PlatformOverride" +#string STR_BUS_OVERRIDE #language en-US "BusSpecificDriverOverride" +#string STR_DRIVER_DIAG #language en-US "DriverDiagnostics" +#string STR_DRIVER_DIAG2 #language en-US "DriverDiagnostics2" +#string STR_DRIVER_CN #language en-US "ComponentName" +#string STR_DRIVER_CN2 #language en-US "ComponentName2" +#string STR_PLAT_DRV_CFG #language en-US "PlatformtoDriverConfiguration" +#string STR_DRIVER_VERSION #language en-US "SupportedEfiSpecVersion" + +// Console +#string STR_TXT_IN #language en-US "SimpleTextIn" +#string STR_TXT_IN_EX #language en-US "SimpleTextInEx" +#string STR_TXT_OUT #language en-US "SimpleTextOut" +#string STR_SIM_POINTER #language en-US "SimplePointer" +#string STR_ABS_POINTER #language en-US "AbsolutePointer" +#string STR_SERIAL_IO #language en-US "SerialIO" +#string STR_GRAPHICS_OUTPUT #language en-US "GraphicsOutput" +#string STR_EDID_DISCOVERED #language en-US "EDIDDiscovered" +#string STR_EDID_ACTIVE #language en-US "EDIDActive" +#string STR_EDID_OVERRIDE #language en-US "EDIDOverride" +#string STR_CON_IN #language en-US "ConsoleIn" +#string STR_CON_OUT #language en-US "ConsoleOut" +#string STR_STD_ERR #language en-US "StdErr" + +// Media +#string STR_LOAD_FILE #language en-US "LoadFile" +#string STR_LOAD_FILE2 #language en-US "LoadFile2" +#string STR_SIMPLE_FILE_SYS #language en-US "SimpleFileSystem" +#string STR_FILE_INFO #language en-US "FileInfo" +#string STR_FILE_SYS_INFO #language en-US "FileSystemInfo" +#string STR_TAPE_IO #language en-US "TapeIO" +#string STR_DISK_IO #language en-US "DiskIO" +#string STR_DISK_IO2 #language en-US "DiskIO2" +#string STR_BLK_IO #language en-US "BlockIO" +#string STR_UC #language en-US "UnicodeCollation" +#string STR_UC2 #language en-US "UnicodeCollation2" +#string STR_ADAPTER_INFO #language en-US "AdapterInfo" + +// PCI +#string STR_PCIRB_IO #language en-US "PCIRootBridgeIO" +#string STR_PCI_IO #language en-US "PCIIO" + +// SCSI +#string STR_SCSI_PT #language en-US "SCSIPassThru" +#string STR_SCSI_IO #language en-US "SCSIIO" +#string STR_SCSI_PT_EXT #language en-US "ExtendedSCSIPassThru" + +// iSCSI +#string STR_ISCSI #language en-US "iSCSIInitiatorName" + +// USB +#string STR_USB_IO #language en-US "USBIO" +#string STR_USB_HC #language en-US "USBHostControler" +#string STR_USB_HC2 #language en-US "USBHostController2" + +// Debug +#string STR_DEBUG_SUPPORT #language en-US "DebugSupport" +#string STR_DEBUG_PORT #language en-US "DebugPort" + +#string STR_DECOMPRESS #language en-US "Decompress" + +#string STR_ACPI_TABLE #language en-US "AcpiTable" + +#string STR_EBC_INTERPRETER #language en-US "EBCInterpreter" + +// Network +#string STR_SNP #language en-US "SimpleNetwork" +#string STR_NII #language en-US "NetworkInterfaceIdentifier" +#string STR_NII_31 #language en-US "NetworkInterfaceIdentifier31" +#string STR_PXE_BC #language en-US "PXEBaseCode" +#string STR_PXE_CB #language en-US "PXECallback" +#string STR_BIS #language en-US "BIS" +#string STR_MNP_SB #language en-US "ManagedNetworkServiceBinding" +#string STR_MNP #language en-US "ManagedNetwork" + +#string STR_ARP_SB #language en-US "ARPServiceBinding" +#string STR_ARP #language en-US "ARP" +#string STR_DHCPV4_SB #language en-US "DHCPv4ServiceBinding" +#string STR_DHCPV4 #language en-US "DHCPv4" +#string STR_TCPV4_SB #language en-US "TCPv4ServiceBinding" +#string STR_TCPV4 #language en-US "TCPv4" +#string STR_IPV4_SB #language en-US "IPv4ServiceBinding" +#string STR_IPV4 #language en-US "IPv4" +#string STR_IPV4_CFG #language en-US "IPv4Config" +#string STR_IPV4_CFG2 #language en-US "IPv4Config2" +#string STR_UDPV4_SB #language en-US "UDPv4ServiceBinding" +#string STR_UDPV4 #language en-US "UDPv4" +#string STR_MTFTPV4_SB #language en-US "MTFTPv4ServiceBinding" +#string STR_MTFTPV4 #language en-US "MTFTPv4" + +// Security +#string STR_HASH_SB #language en-US "HashServiceBinding" +#string STR_HASH #language en-US "Hash" +#string STR_AUTH_INFO #language en-US "AuthenticationInfo" + +// HII +#string STR_HII_FONT #language en-US "HIIFont" +#string STR_HII_STRING #language en-US "HIIString" +#string STR_HII_IMAGE #language en-US "HIIImage" +#string STR_HII_DATABASE #language en-US "HIIDatabase" +#string STR_HII_CONFIG_ROUT #language en-US "HIIConfigRouting" +#string STR_HII_CONFIG_ACC #language en-US "HIIConfigAccess" +#string STR_HII_FORM_BROWSER2 #language en-US "HIIFormBrowser2" + +// Shell +#string STR_SHELL_PARAMETERS #language en-US "ShellParameters" +#string STR_SHELL #language en-US "Shell" +#string STR_SHELL_DYNAMIC #language en-US "ShellDynamicCommand" + +#string STR_EFI_GLOBAL_VARIABLE #language en-US "EFIGlobalVariable" + +// NT32 emulation +#string STR_WINNT_THUNK #language en-US "WinNTThunk" +#string STR_WINNT_DRIVER_IO #language en-US "WinNTDriverIO" +#string STR_WINNT_SERIAL_PORT #language en-US "WinNTSerialPort" + +// deprecated protocols +#string STR_SHELL_INTERFACE #language en-US "ShellInterface" +#string STR_SHELL_ENV #language en-US "ShellEnvironment" +#string STR_SHELL_ENV2 #language en-US "ShellEnvironment2" +#string STR_SHELL_DP_MAP #language en-US "ShellDevicePathMap" +#string STR_SHELL_ALIAS #language en-US "ShellAlias" +#string STR_DEVICE_IO #language en-US "DeviceIO" +#string STR_TCP #language en-US "TCP" +#string STR_UGA_DRAW #language en-US "UGADraw" +#string STR_UGA_IO #language en-US "UGAIO" +#string STR_ESP #language en-US "EFISystemPartition" +#string STR_GPT_NBR #language en-US "LegacyMBR" +#string STR_DRIVER_CONFIG #language en-US "DriverConfiguration" +#string STR_DRIVER_CONFIG2 #language en-US "DriverConfiguration2" +#string STR_ISA_IO #language en-US "ISAIO" +#string STR_ISA_ACPI #language en-US "ISAACPI" +#string STR_HII_FORM_BROWSER #language en-US "HIIFormBrowser" +#string STR_HII #language en-US "HII" +#string STR_HII_FORM_CALLBACK #language en-US "HIICallback" + +#string STR_TXT_OUT_DUMP_HEADER #language en-US " Address: %%H%X%%N Attrib %02x" +#string STR_TXT_OUT_DUMP_LINE #language en-US "\r\n %c mode %d: Col %d Row %d" + +#string STR_DRIVER_FAM_OVERRIDE #language en-US "DriverFamilyOverride" +#string STR_PCD #language en-US "Pcd" +#string STR_TCG #language en-US "Tcg" +#string STR_HII_PACKAGE_LIST #language en-US "HiiPackageList" + +#string STR_IP6_SB #language en-US "Ip6ServiceBinding" +#string STR_IP6 #language en-US "Ip6" +#string STR_IP6_CONFIG #language en-US "Ip6Config" +#string STR_MTFTP6_SB #language en-US "Mtftp6ServiceBinding" +#string STR_MTFTP6 #language en-US "Mtftp6" +#string STR_DHCP6_SB #language en-US "Dhcp6ServiceBinding" +#string STR_DHCP6 #language en-US "Dhcp6" +#string STR_UDP6_SB #language en-US "Udp6ServiceBinding" +#string STR_UDP6 #language en-US "Udp6" +#string STR_TCP6_SB #language en-US "Tcp6ServiceBinding" +#string STR_TCP6 #language en-US "Tcp6" +#string STR_VLAN_CONFIG #language en-US "VlanConfig" +#string STR_EAP #language en-US "Eap" +#string STR_EAP_MGMT #language en-US "EapManagement" +#string STR_FTP4_SB #language en-US "Ftp4ServiceBinding" +#string STR_FTP4 #language en-US "Ftp4" +#string STR_IP_SEC_CONFIG #language en-US "IpSecConfig" +#string STR_DH #language en-US "DriverHealth" +#string STR_DEF_IMG_LOAD #language en-US "DeferredImageLoad" +#string STR_USER_CRED #language en-US "UserCredential" +#string STR_USER_MNGR #language en-US "UserManager" +#string STR_ATA_PASS_THRU #language en-US "AtaPassThru" +#string STR_FW_MGMT #language en-US "FirmwareManagement" +#string STR_IP_SEC #language en-US "IpSec" +#string STR_IP_SEC2 #language en-US "IpSec2" +#string STR_KMS #language en-US "Kms" +#string STR_BLK_IO2 #language en-US "BlockIo2" +#string STR_SSC #language en-US "StorageSecurityCommand" +#string STR_UCRED2 #language en-US "UserCredential2" + +#string STR_PCDINFOPROT #language en-US "GetPcdInfoProtocol" +#string STR_BDS_ARCH #language en-US "BdsArch" +#string STR_CPU_ARCH #language en-US "CpuArch" +#string STR_MET_ARCH #language en-US "MetronomeArch" +#string STR_MON_ARCH #language en-US "MonotonicCounterArch" +#string STR_RTC_ARCH #language en-US "RealTimeClockArch" +#string STR_RESET_ARCH #language en-US "ResetArch" +#string STR_RT_ARCH #language en-US "RuntimeArch" +#string STR_SEC_ARCH #language en-US "SecurityArch" +#string STR_TIMER_ARCH #language en-US "TimerArch" +#string STR_VAR_ARCH #language en-US "VariableWriteArch" +#string STR_V_ARCH #language en-US "VariableArch" +#string STR_SECP #language en-US "SecurityPolicy" +#string STR_WDT_ARCH #language en-US "WatchdogTimerArch" +#string STR_SCR #language en-US "StatusCodeRuntime" +#string STR_SMB_HC #language en-US "SmbusHc" +#string STR_FV_2 #language en-US "FirmwareVolume2" +#string STR_FV_BLOCK #language en-US "FirmwareVolumeBlock" +#string STR_CAP_ARCH #language en-US "CapsuleArch" +#string STR_MP_SERVICE #language en-US "MpService" +#string STR_HBRAP #language en-US "PciHostBridgeResourceAllocation" +#string STR_PCIP #language en-US "PciPlatform" +#string STR_PCIO #language en-US "PciOverride" +#string STR_PCIE #language en-US "PciEnumerationComplete" +#string STR_IPCID #language en-US "IncompatiblePciDeviceSupport" +#string STR_PCIHPI #language en-US "PciHotPlugInit" +#string STR_PCIHPR #language en-US "PciHotPlugRequest" +#string STR_SMBIOS #language en-US "Smbios" +#string STR_S3_SAVE #language en-US "S3SaveState" +#string STR_S3_S_SMM #language en-US "S3SmmSaveState" +#string STR_RSC #language en-US "RscHandler" +#string STR_S_RSC #language en-US "SmmRscHandler" +#string STR_ACPI_SDT #language en-US "AcpiSdt" +#string STR_SIO #language en-US "Sio" +#string STR_S_CPU2 #language en-US "SmmCpuIo2" +#string STR_S_BASE2 #language en-US "SmmBase2" +#string STR_S_ACC_2 #language en-US "SmmAccess2" +#string STR_S_CON_2 #language en-US "SmmControl2" +#string STR_S_CONFIG #language en-US "SmmConfig" +#string STR_S_RTL #language en-US "SmmReadyToLock" +#string STR_DS_RTL #language en-US "DxeSmmReadyToLock" +#string STR_S_COMM #language en-US "SmmCommunication" +#string STR_S_STAT #language en-US "SmmStatusCode" +#string STR_S_CPU #language en-US "SmmCpu" +#string STR_S_PCIRBIO #language en-US "SmmPCIRootBridgeIO" +#string STR_S_SWD #language en-US "SmmSwDispatch2" +#string STR_S_SXD #language en-US "SmmSxDispatch2" +#string STR_S_PTD2 #language en-US "SmmPeriodicTimerDispatch2" +#string STR_S_UD2 #language en-US "SmmUsbDispatch2" +#string STR_S_GD2 #language en-US "SmmGpiDispatch2" +#string STR_S_SBD2 #language en-US "SmmStandbyButtonDispatch2" +#string STR_S_PBD2 #language en-US "SmmPowerButtonDispatch2" +#string STR_S_ITD2 #language en-US "SmmIoTrapDispatch2" +#string STR_PCD #language en-US "Pcd" +#string STR_FVB2 #language en-US "FirmwareVolumeBlock2" +#string STR_CPUIO2 #language en-US "CpuIo2" +#string STR_LEGACY_R2 #language en-US "LegacyRegion2" +#string STR_S2ARCH #language en-US "Security2Arch" +#string STR_EODXE #language en-US "SmmEndOfDxe" +#string STR_ISAHC #language en-US "IsaHc" +#string STR_ISAHC_B #language en-US "IsaHcServiceBinding" +#string STR_SIO_C #language en-US "SioControl" +#string STR_GET_PCD #language en-US "GetPcdInfo" +#string STR_I2C_M #language en-US "I2cMaster" +#string STR_I2CIO #language en-US "I2cIo" +#string STR_I2CEN #language en-US "I2cEnumerate" +#string STR_I2C_H #language en-US "I2cHost" +#string STR_I2C_BCM #language en-US "I2cBusConfigurationManagement" +#string STR_TCG2 #language en-US "Tcg2" +#string STR_TIMESTAMP #language en-US "Timestamp" +#string STR_RNG #language en-US "Rng" +#string STR_NVMEPT #language en-US "NvmExpressPassThru" +#string STR_H2_SB #language en-US "Hash2ServiceBinding" +#string STR_HASH2 #language en-US "Hash2" +#string STR_BIO_C #language en-US "BlockIoCrypto" +#string STR_SCR #language en-US "SmartCardReader" +#string STR_SCE #language en-US "SmartCardEdge" +#string STR_USB_FIO #language en-US "UsbFunctionIo" +#string STR_BC_HC #language en-US "BluetoothHc" +#string STR_BC_IO_SB #language en-US "BluetoothIoServiceBinding" +#string STR_BC_IO #language en-US "BluetoothIo" +#string STR_BC_C #language en-US "BluetoothConfig" +#string STR_REG_EXP #language en-US "RegularExpression" +#string STR_B_MGR_P #language en-US "BootManagerPolicy" +#string STR_CKH #language en-US "ConfigKeywordHandler" +#string STR_WIFI #language en-US "WiFi" +#string STR_EAP_M #language en-US "EapManagement2" +#string STR_EAP_C #language en-US "EapConfiguration" +#string STR_PKCS7 #language en-US "Pkcs7Verify" +#string STR_NET_DNS4_SB #language en-US "Dns4ServiceBinding" +#string STR_NET_DNS4 #language en-US "Dns4" +#string STR_NET_DNS6_SB #language en-US "Dns6ServiceBinding" +#string STR_NET_DNS6 #language en-US "Dns6" +#string STR_NET_HTTP_SB #language en-US "HttpServiceBinding" +#string STR_NET_HTTP #language en-US "Http" +#string STR_NET_HTTP_U #language en-US "HttpUtilities" +#string STR_REST #language en-US "Rest" +#string STR_REST_EX #language en-US "RestEx" +#string STR_REDFISH_DISCOVER #language en-US "RedfishDiscover" + +#string STR_MM_EOD #language en-US "MmEndOfDxe" +#string STR_MM_ITD #language en-US "MmIoTrapDispatch" +#string STR_MM_PBD #language en-US "MmPowerButtonDispatch" +#string STR_MM_SBD #language en-US "MmStandbyButtonDispatch" +#string STR_MM_GD #language en-US "MmGpiDispatch" +#string STR_MM_UD #language en-US "MmUsbDispatch" +#string STR_MM_PTD #language en-US "MmPeriodicTimerDispatch" +#string STR_MM_SXD #language en-US "MmSxDispatch" +#string STR_MM_SWD #language en-US "MmSwDispatch" +#string STR_MM_PRBI #language en-US "MmPciRootBridgeIo" +#string STR_MM_CPU #language en-US "MmCpu" +#string STR_MM_STACODE #language en-US "MmStatusCode" +#string STR_DXEMM_RTL #language en-US "DxeMmReadyToLock" +#string STR_MM_CONFIG #language en-US "MmConfiguration" +#string STR_MM_RTL #language en-US "MmReadyToLock" +#string STR_MM_CONTROL #language en-US "MmControl" +#string STR_MM_ACCESS #language en-US "MmAccess" +#string STR_MM_BASE #language en-US "MmBase" +#string STR_MM_CPUIO #language en-US "MmCpuIo" +#string STR_MM_RH #language en-US "MmRscHandler" +#string STR_MM_COM #language en-US "MmCommunication" + +#string STR_TLS_SB #language en-US "TlsServiceBinding" +#string STR_TLS #language en-US "Tls" +#string STR_TLS_CONFIG #language en-US "TlsConfiguration" +#string STR_SUPPLICANT_SB #language en-US "SupplicantServiceBinding" +#string STR_SUPPLICANT #language en-US "Supplicant" + +#string STR_WIFI2 #language en-US "WiFi2" +#string STR_RAMDISK #language en-US "RamDisk" +#string STR_HII_ID #language en-US "HiiImageDecoder" +#string STR_HII_IE #language en-US "HiiImageEx" +#string STR_SD_MPT #language en-US "SdMmcPassThru" +#string STR_ERASE_BLOCK #language en-US "EraseBlock" + +#string STR_BLUETOOTH_ATTR #language en-US "BluetoothAttribute" +#string STR_BLUETOOTH_ATTR_SB #language en-US "BluetoothAttributeServiceBinding" +#string STR_BLUETOOTH_LE_CONFIG #language en-US "BluetoothLeConfig" +#string STR_UFS_DEV_CONFIG #language en-US "UfsDeviceConfig" +#string STR_HTTP_BOOT_CALL #language en-US "HttpBootCallback" +#string STR_RESET_NOTI #language en-US "ResetNotification" +#string STR_PARTITION_INFO #language en-US "PartitionInfo" +#string STR_HII_POPUP #language en-US "HiiPopup" + +#string STR_IDE_CONT_INIT #language en-US "IdeControllerInit" +#string STR_DISK_INFO #language en-US "DiskInfo" +#string STR_BLOCKIO_INFO #language en-US " %s%sMId:%%H%x%%N bsize %%H%x%%N, lblock %lx (%,ld), %s %s %s" +#string STR_DEBUGSUPPORT_INFO #language en-US " Isa = %s" +#string STR_DEBUGSUPPORT_UNKNOWN #language en-US " Unknown (%%H%s%%N)" + +#string STR_PCIRB_DUMP_PH #language en-US " ParentHandle..: %%H%x%%N\r\n" +#string STR_PCIRB_DUMP_SEG #language en-US " Segment #.....: %%H%x%%N\r\n" +#string STR_PCIRB_DUMP_ATT #language en-US " Attributes....: %%H%x%%N\r\n" +#string STR_PCIRB_DUMP_SUPPORTS #language en-US " Supports......: %%H%x%%N\r\n" +#string STR_PCIRB_DUMP_BUS #language en-US " BUS : " +#string STR_PCIRB_DUMP_MEM #language en-US " MEM : " +#string STR_PCIRB_DUMP_IO #language en-US " IO : " +#string STR_PCIRB_DUMP_TITLE #language en-US " Type Flag Base Limit Gran\r\n" + " ==== ==== ================ ================ ====" +#string STR_PCIIO_DUMP_MAIN #language en-US " Segment #.....: %02x\r\n" + " Bus #.........: %02x\r\n" + " Device #......: %02x\r\n" + " Function #....: %02x\r\n" + " ROM Size......: %lx\r\n" + " ROM Location..: %08x\r\n" + " Vendor ID.....: %04x\r\n" + " Device ID.....: %04x\r\n" + " Class Code....: %02x %02x %02x\r\n" + " Configuration Header :" +#string STR_USBIO_DUMP_MAIN #language en-US " Interface Number #.....: %02x\r\n" + " Interface Class #......: %02x\r\n" + " Interface Subclass #...: %02x\r\n" + " Interface Protocol #...: %02x" + +#string STR_LI_DUMP_NAME #language en-US " Name..........: %%H%s%%N\r\n" + +#string STR_LI_DUMP_MAIN #language en-US " Revision......: %%H0x%08x%%N\r\n" + " ParentHandle..: %%H%x%%N\r\n" + " SystemTable...: %%H%x%%N\r\n" + " DeviceHandle..: %%H%x%%N\r\n" + " FilePath......: %%H%s%%N\r\n" + " PdbFileName...: %%H%a%%N\r\n" + " OptionsSize...: %%H%x%%N\r\n" + " LoadOptions...: %%H%x%%N\r\n" + " ImageBase.....: %%H%x%%N\r\n" + " ImageSize.....: %%H%Lx%%N\r\n" + " CodeType......: %%H%s%%N\r\n" + " DataType......: %%H%s%%N\r\n" + " Unload........: %%H%x%%N" + +#string STR_GOP_DUMP_MAIN #language en-US " Max Mode..............: %%H0x%08x%%N\r\n" + " Current Mode..........: %%H0x%08x%%N\r\n" + " Frame Buffer Base.....: %%H0x%L016x%%N\r\n" + " Frame Buffer Size.....: %%H0x%L016x%%N\r\n" + " Mode Info Size........: %%H0x%L016x%%N\r\n" + " Information\r\n" + " Version.............: %%H0x%08x%%N\r\n" + " HorizontalResolution: %%H%d%%N\r\n" + " VerticalResolution..: %%H%d%%N\r\n" + " Pixel Format........: %%H%s%%N\r\n" + " Pixels / Scan Line..: %%H%d%%N\r\n" + " Pixel Info\r\n" + " RedMask...........: %%H0x%08x%%N\r\n" + " GreenMask.........: %%H0x%08x%%N\r\n" + " BlueMask..........: %%H0x%08x%%N\r\n" + +#string STR_GOP_RES_LIST_MAIN #language en-US " Supported Resolution List" +#string STR_GOP_RES_LIST_ENTRY #language en-US "\r\n" + " Resolution[%%H%d%%N]:\r\n" + " Horizontal........: %%H%d%%N\r\n" + " Vertical..........: %%H%d%%N" +#string STR_BSDO_DUMP_MAIN #language en-US " Drv[%02x] File:%%H%s%%N" +#string STR_EDID_DISCOVERED_MAIN #language en-US " EDID Discovered Size : %%H0x%08x%%N\r\n" +#string STR_EDID_DISCOVERED_DATA #language en-US " EDID Discovered Data :\r\n" +#string STR_EDID_ACTIVE_MAIN #language en-US " EDID Active Size : %%H0x%08x%%N\r\n" +#string STR_EDID_ACTIVE_DATA #language en-US " EDID Active Data :\r\n" + +#string STR_GET_SUPP_TYPES_FAILED #language en-US "Unable to get supported types - %%H%r%%N\r\n" +#string STR_SUPP_TYPE_HEADER #language en-US " Supported Information Types: \r\n" +#string STR_GUID_NUMBER #language en-US " Guid[%%H%d%%N] : %g" +#string STR_GUID_STRING #language en-US " - %%B%s%%N\r\n" +#string STR_GETINFO_FAILED #language en-US " Unable to get information - %%H%r%%N\r\n" +#string STR_MEDIA_STATE #language en-US " MediaState: %%H0x%08x - %r%%N\r\n" +#string STR_NETWORK_BOOT_INFO #language en-US "" + " iSsciIpv4BootCapablity : %%H%d%%N\r\n" + " iScsiIpv6BootCapablity : %%H%d%%N\r\n" + " FCoeBootCapablity : %%H%d%%N\r\n" + " OffloadCapability : %%H%d%%N\r\n" + " iScsiMpioCapability : %%H%d%%N\r\n" + " iScsiIpv4Boot : %%H%d%%N\r\n" + " iScsiIpv6Boot : %%H%d%%N\r\n" + " FCoeBoot : %%H%d%%N\r\n" +#string STR_SAN_MAC_ADDRESS_INFO #language en-US " SanMacAddress: %%H%02x-%02x-%02x-%02x-%02x-%02x%%N \r\n" +#string STR_UNDI_IPV6_INFO #language en-US " UNDI IPv6 Supported: %%H%d%%N \r\n" +#string STR_UNKNOWN_INFO_TYPE #language en-US " The 'InformationType' - %%H%g%%N can't be recongnized\r\n" + +#string STR_FMP_IMAGEID_NON_UNIQUE #language en-US " The ImageId value for each Firmware Image is not unique.\r\n" +#string STR_FMP_IMAGE_INFO_SIZE #language en-US " ImageInfoSize: %%H0x%L016x%%N\r\n" +#string STR_FMP_DESCRIPTOR_VERSION #language en-US " DescriptorVersion: %%H%d%%N\r\n" +#string STR_FMP_DESCRIPTOR_COUNT #language en-US " DescriptorCount : %%H%d%%N\r\n" +#string STR_FMP_DESCRIPTOR_SIZE #language en-US " DescriptorSize : %%H0x%Lx%%N\r\n" +#string STR_FMP_PACKAGE_VERSION #language en-US " PackageVersion : %%H0x%08x%%N\r\n" +#string STR_FMP_PACKAGE_VERSION_NAME #language en-US " PackageVersionName : %%H%s%%N\r\n" +#string STR_FMP_IMAGE_DESCRIPTOR_INFO #language en-US "" + " ImageInfo[%%H%d%%N]:\r\n" + " =============\r\n" + " ImageIndex : %%H%d%%N\r\n" + " ImageTypeId : %%H%g%%N\r\n" + " ImageId : %%H%L016x%%N\r\n" + " ImageIdName : %%H%s%%N\r\n" + " Version : %%H0x%08x%%N\r\n" + " VersionName : %%H%s%%N\r\n" + " Size : %%H0x%L016x%%N\r\n" + " AttributesSupported : %%H0x%L016x%%N\r\n" + " AttributesSetting : %%H%s%%N\r\n" + " Compatibilities : %%H0x%L016x%%N\r\n" + " LowestSupportedImageVersion : %%H0x%08x%%N\r\n" + " LastAttemptVersion : %%H0x%08x%%N\r\n" + " LastAttemptStatus : %%H0x%08x%%N\r\n" + " HardwareInstance : %%H0x%08x%%N\r\n" + +#string STR_FMP_IMAGE_DESCRIPTOR_INFO_V1 #language en-US "" + " ImageInfo[%%H%d%%N]:\r\n" + " =============\r\n" + " ImageIndex : %%H%d%%N\r\n" + " ImageTypeId : %%H%g%%N\r\n" + " ImageId : %%H%L016x%%N\r\n" + " ImageIdName : %%H%s%%N\r\n" + " Version : %%H0x%08x%%N\r\n" + " VersionName : %%H%s%%N\r\n" + " Size : %%H0x%L016x%%N\r\n" + " AttributesSupported : %%H0x%L016x%%N\r\n" + " AttributesSetting : %%H%s%%N\r\n" + " Compatibilities : %%H0x%L016x%%N\r\n" + +#string STR_FMP_IMAGE_DESCRIPTOR_INFO_V2 #language en-US "" + " ImageInfo[%%H%d%%N]:\r\n" + " =============\r\n" + " ImageIndex : %%H%d%%N\r\n" + " ImageTypeId : %%H%g%%N\r\n" + " ImageId : %%H%L016x%%N\r\n" + " ImageIdName : %%H%s%%N\r\n" + " Version : %%H0x%08x%%N\r\n" + " VersionName : %%H%s%%N\r\n" + " Size : %%H0x%L016x%%N\r\n" + " AttributesSupported : %%H0x%L016x%%N\r\n" + " AttributesSetting : %%H%s%%N\r\n" + " Compatibilities : %%H0x%L016x%%N\r\n" + " LowestSupportedImageVersion : %%H0x%08x%%N\r\n" + +#string STR_PARTINFO_DUMP_TYPE_OTHER #language en-US " Partition Type : Other" +#string STR_PARTINFO_DUMP_TYPE_MBR #language en-US " Partition Type : MBR" +#string STR_PARTINFO_DUMP_TYPE_GPT #language en-US " Partition Type : GPT" +#string STR_PARTINFO_DUMP_EFI_SYS_PART #language en-US " EFI System Partition : Yes" +#string STR_PARTINFO_DUMP_NOT_EFI_SYS_PART #language en-US " EFI System Partition : No" diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.c new file mode 100644 index 00000000..f3c8e9d4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.c @@ -0,0 +1,740 @@ +/** @file + ACPI parser + + Copyright (c) 2016 - 2021, Arm Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include "AcpiParser.h" +#include "AcpiView.h" +#include "AcpiViewConfig.h" + +STATIC UINT32 gIndent; +STATIC UINT32 mTableErrorCount; +STATIC UINT32 mTableWarningCount; + +STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo; + +/** + An ACPI_PARSER array describing the ACPI header. +**/ +STATIC CONST ACPI_PARSER AcpiHeaderParser[] = { + PARSE_ACPI_HEADER (&AcpiHdrInfo) +}; + +/** + This function resets the ACPI table error counter to Zero. +**/ +VOID +ResetErrorCount ( + VOID + ) +{ + mTableErrorCount = 0; +} + +/** + This function returns the ACPI table error count. + + @retval Returns the count of errors detected in the ACPI tables. +**/ +UINT32 +GetErrorCount ( + VOID + ) +{ + return mTableErrorCount; +} + +/** + This function resets the ACPI table warning counter to Zero. +**/ +VOID +ResetWarningCount ( + VOID + ) +{ + mTableWarningCount = 0; +} + +/** + This function returns the ACPI table warning count. + + @retval Returns the count of warning detected in the ACPI tables. +**/ +UINT32 +GetWarningCount ( + VOID + ) +{ + return mTableWarningCount; +} + +/** + This function increments the ACPI table error counter. +**/ +VOID +EFIAPI +IncrementErrorCount ( + VOID + ) +{ + mTableErrorCount++; +} + +/** + This function increments the ACPI table warning counter. +**/ +VOID +EFIAPI +IncrementWarningCount ( + VOID + ) +{ + mTableWarningCount++; +} + +/** + This function verifies the ACPI table checksum. + + This function verifies the checksum for the ACPI table and optionally + prints the status. + + @param [in] Log If TRUE log the status of the checksum. + @param [in] Ptr Pointer to the start of the table buffer. + @param [in] Length The length of the buffer. + + @retval TRUE The checksum is OK. + @retval FALSE The checksum failed. +**/ +BOOLEAN +EFIAPI +VerifyChecksum ( + IN BOOLEAN Log, + IN UINT8* Ptr, + IN UINT32 Length + ) +{ + UINTN ByteCount; + UINT8 Checksum; + UINTN OriginalAttribute; + + // + // set local variables to suppress incorrect compiler/analyzer warnings + // + OriginalAttribute = 0; + ByteCount = 0; + Checksum = 0; + + while (ByteCount < Length) { + Checksum += *(Ptr++); + ByteCount++; + } + + if (Log) { + OriginalAttribute = gST->ConOut->Mode->Attribute; + if (Checksum == 0) { + if (GetColourHighlighting ()) { + gST->ConOut->SetAttribute ( + gST->ConOut, + EFI_TEXT_ATTR (EFI_GREEN, + ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)) + ); + } + Print (L"Table Checksum : OK\n\n"); + } else { + IncrementErrorCount (); + if (GetColourHighlighting ()) { + gST->ConOut->SetAttribute ( + gST->ConOut, + EFI_TEXT_ATTR (EFI_RED, + ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)) + ); + } + Print (L"Table Checksum : FAILED (0x%X)\n\n", Checksum); + } + if (GetColourHighlighting ()) { + gST->ConOut->SetAttribute (gST->ConOut, OriginalAttribute); + } + } + + return (Checksum == 0); +} + +/** + This function performs a raw data dump of the ACPI table. + + @param [in] Ptr Pointer to the start of the table buffer. + @param [in] Length The length of the buffer. +**/ +VOID +EFIAPI +DumpRaw ( + IN UINT8* Ptr, + IN UINT32 Length + ) +{ + UINTN ByteCount; + UINTN PartLineChars; + UINTN AsciiBufferIndex; + CHAR8 AsciiBuffer[17]; + + ByteCount = 0; + AsciiBufferIndex = 0; + + Print (L"Address : 0x%p\n", Ptr); + Print (L"Length : %d\n", Length); + + while (ByteCount < Length) { + if ((ByteCount & 0x0F) == 0) { + AsciiBuffer[AsciiBufferIndex] = '\0'; + Print (L" %a\n%08X : ", AsciiBuffer, ByteCount); + AsciiBufferIndex = 0; + } else if ((ByteCount & 0x07) == 0) { + Print (L"- "); + } + + if ((*Ptr >= ' ') && (*Ptr < 0x7F)) { + AsciiBuffer[AsciiBufferIndex++] = *Ptr; + } else { + AsciiBuffer[AsciiBufferIndex++] = '.'; + } + + Print (L"%02X ", *Ptr++); + + ByteCount++; + } + + // Justify the final line using spaces before printing + // the ASCII data. + PartLineChars = (Length & 0x0F); + if (PartLineChars != 0) { + PartLineChars = 48 - (PartLineChars * 3); + if ((Length & 0x0F) <= 8) { + PartLineChars += 2; + } + while (PartLineChars > 0) { + Print (L" "); + PartLineChars--; + } + } + + // Print ASCII data for the final line. + AsciiBuffer[AsciiBufferIndex] = '\0'; + Print (L" %a\n\n", AsciiBuffer); +} + +/** + This function traces 1 byte of data as specified in the format string. + + @param [in] Format The format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +VOID +EFIAPI +DumpUint8 ( + IN CONST CHAR16* Format, + IN UINT8* Ptr + ) +{ + Print (Format, *Ptr); +} + +/** + This function traces 2 bytes of data as specified in the format string. + + @param [in] Format The format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +VOID +EFIAPI +DumpUint16 ( + IN CONST CHAR16* Format, + IN UINT8* Ptr + ) +{ + Print (Format, *(UINT16*)Ptr); +} + +/** + This function traces 4 bytes of data as specified in the format string. + + @param [in] Format The format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +VOID +EFIAPI +DumpUint32 ( + IN CONST CHAR16* Format, + IN UINT8* Ptr + ) +{ + Print (Format, *(UINT32*)Ptr); +} + +/** + This function traces 8 bytes of data as specified by the format string. + + @param [in] Format The format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +VOID +EFIAPI +DumpUint64 ( + IN CONST CHAR16* Format, + IN UINT8* Ptr + ) +{ + // Some fields are not aligned and this causes alignment faults + // on ARM platforms if the compiler generates LDRD instructions. + // Perform word access so that LDRD instructions are not generated. + UINT64 Val; + + Val = *(UINT32*)(Ptr + sizeof (UINT32)); + + Val = LShiftU64(Val,32); + Val |= (UINT64)*(UINT32*)Ptr; + + Print (Format, Val); +} + +/** + This function traces 3 characters which can be optionally + formated using the format string if specified. + + If no format string is specified the Format must be NULL. + + @param [in] Format Optional format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +VOID +EFIAPI +Dump3Chars ( + IN CONST CHAR16* Format OPTIONAL, + IN UINT8* Ptr + ) +{ + Print ( + (Format != NULL) ? Format : L"%c%c%c", + Ptr[0], + Ptr[1], + Ptr[2] + ); +} + +/** + This function traces 4 characters which can be optionally + formated using the format string if specified. + + If no format string is specified the Format must be NULL. + + @param [in] Format Optional format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +VOID +EFIAPI +Dump4Chars ( + IN CONST CHAR16* Format OPTIONAL, + IN UINT8* Ptr + ) +{ + Print ( + (Format != NULL) ? Format : L"%c%c%c%c", + Ptr[0], + Ptr[1], + Ptr[2], + Ptr[3] + ); +} + +/** + This function traces 6 characters which can be optionally + formated using the format string if specified. + + If no format string is specified the Format must be NULL. + + @param [in] Format Optional format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +VOID +EFIAPI +Dump6Chars ( + IN CONST CHAR16* Format OPTIONAL, + IN UINT8* Ptr + ) +{ + Print ( + (Format != NULL) ? Format : L"%c%c%c%c%c%c", + Ptr[0], + Ptr[1], + Ptr[2], + Ptr[3], + Ptr[4], + Ptr[5] + ); +} + +/** + This function traces 8 characters which can be optionally + formated using the format string if specified. + + If no format string is specified the Format must be NULL. + + @param [in] Format Optional format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +VOID +EFIAPI +Dump8Chars ( + IN CONST CHAR16* Format OPTIONAL, + IN UINT8* Ptr + ) +{ + Print ( + (Format != NULL) ? Format : L"%c%c%c%c%c%c%c%c", + Ptr[0], + Ptr[1], + Ptr[2], + Ptr[3], + Ptr[4], + Ptr[5], + Ptr[6], + Ptr[7] + ); +} + +/** + This function traces 12 characters which can be optionally + formated using the format string if specified. + + If no format string is specified the Format must be NULL. + + @param [in] Format Optional format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +VOID +EFIAPI +Dump12Chars ( + IN CONST CHAR16* Format OPTIONAL, + IN UINT8* Ptr + ) +{ + Print ( + (Format != NULL) ? Format : L"%c%c%c%c%c%c%c%c%c%c%c%c", + Ptr[0], + Ptr[1], + Ptr[2], + Ptr[3], + Ptr[4], + Ptr[5], + Ptr[6], + Ptr[7], + Ptr[8], + Ptr[9], + Ptr[10], + Ptr[11] + ); +} + +/** + This function indents and prints the ACPI table Field Name. + + @param [in] Indent Number of spaces to add to the global table indent. + The global table indent is 0 by default; however + this value is updated on entry to the ParseAcpi() + by adding the indent value provided to ParseAcpi() + and restored back on exit. + Therefore the total indent in the output is + dependent on from where this function is called. + @param [in] FieldName Pointer to the Field Name. +**/ +VOID +EFIAPI +PrintFieldName ( + IN UINT32 Indent, + IN CONST CHAR16* FieldName +) +{ + Print ( + L"%*a%-*s : ", + gIndent + Indent, + "", + (OUTPUT_FIELD_COLUMN_WIDTH - gIndent - Indent), + FieldName + ); +} + +/** + This function is used to parse an ACPI table buffer. + + The ACPI table buffer is parsed using the ACPI table parser information + specified by a pointer to an array of ACPI_PARSER elements. This parser + function iterates through each item on the ACPI_PARSER array and logs the + ACPI table fields. + + This function can optionally be used to parse ACPI tables and fetch specific + field values. The ItemPtr member of the ACPI_PARSER structure (where used) + is updated by this parser function to point to the selected field data + (e.g. useful for variable length nested fields). + + @param [in] Trace Trace the ACPI fields TRUE else only parse the + table. + @param [in] Indent Number of spaces to indent the output. + @param [in] AsciiName Optional pointer to an ASCII string that describes + the table being parsed. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] Length Length of the buffer pointed by Ptr. + @param [in] Parser Pointer to an array of ACPI_PARSER structure that + describes the table being parsed. + @param [in] ParserItems Number of items in the ACPI_PARSER array. + + @retval Number of bytes parsed. +**/ +UINT32 +EFIAPI +ParseAcpi ( + IN BOOLEAN Trace, + IN UINT32 Indent, + IN CONST CHAR8* AsciiName OPTIONAL, + IN UINT8* Ptr, + IN UINT32 Length, + IN CONST ACPI_PARSER* Parser, + IN UINT32 ParserItems +) +{ + UINT32 Index; + UINT32 Offset; + BOOLEAN HighLight; + UINTN OriginalAttribute; + + // + // set local variables to suppress incorrect compiler/analyzer warnings + // + OriginalAttribute = 0; + Offset = 0; + + // Increment the Indent + gIndent += Indent; + + if (Trace && (AsciiName != NULL)){ + HighLight = GetColourHighlighting (); + + if (HighLight) { + OriginalAttribute = gST->ConOut->Mode->Attribute; + gST->ConOut->SetAttribute ( + gST->ConOut, + EFI_TEXT_ATTR(EFI_YELLOW, + ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)) + ); + } + Print ( + L"%*a%-*a :\n", + gIndent, + "", + (OUTPUT_FIELD_COLUMN_WIDTH - gIndent), + AsciiName + ); + if (HighLight) { + gST->ConOut->SetAttribute (gST->ConOut, OriginalAttribute); + } + } + + for (Index = 0; Index < ParserItems; Index++) { + if ((Offset + Parser[Index].Length) > Length) { + + // For fields outside the buffer length provided, reset any pointers + // which were supposed to be updated by this function call + if (Parser[Index].ItemPtr != NULL) { + *Parser[Index].ItemPtr = NULL; + } + + // We don't parse past the end of the max length specified + continue; + } + + if (GetConsistencyChecking () && + (Offset != Parser[Index].Offset)) { + IncrementErrorCount (); + Print ( + L"\nERROR: %a: Offset Mismatch for %s\n" + L"CurrentOffset = %d FieldOffset = %d\n", + AsciiName, + Parser[Index].NameStr, + Offset, + Parser[Index].Offset + ); + } + + if (Trace) { + // if there is a Formatter function let the function handle + // the printing else if a Format is specified in the table use + // the Format for printing + PrintFieldName (2, Parser[Index].NameStr); + if (Parser[Index].PrintFormatter != NULL) { + Parser[Index].PrintFormatter (Parser[Index].Format, Ptr); + } else if (Parser[Index].Format != NULL) { + switch (Parser[Index].Length) { + case 1: + DumpUint8 (Parser[Index].Format, Ptr); + break; + case 2: + DumpUint16 (Parser[Index].Format, Ptr); + break; + case 4: + DumpUint32 (Parser[Index].Format, Ptr); + break; + case 8: + DumpUint64 (Parser[Index].Format, Ptr); + break; + default: + Print ( + L"\nERROR: %a: CANNOT PARSE THIS FIELD, Field Length = %d\n", + AsciiName, + Parser[Index].Length + ); + } // switch + } + // Validating only makes sense if we are tracing + // the parsed table entries, to report by table name. + if (GetConsistencyChecking () && + (Parser[Index].FieldValidator != NULL)) { + Parser[Index].FieldValidator (Ptr, Parser[Index].Context); + } + Print (L"\n"); + } // if (Trace) + + if (Parser[Index].ItemPtr != NULL) { + *Parser[Index].ItemPtr = (VOID*)Ptr; + } + + Ptr += Parser[Index].Length; + Offset += Parser[Index].Length; + } // for + + // Decrement the Indent + gIndent -= Indent; + return Offset; +} + +/** + An array describing the ACPI Generic Address Structure. + The GasParser array is used by the ParseAcpi function to parse and/or trace + the GAS structure. +**/ +STATIC CONST ACPI_PARSER GasParser[] = { + {L"Address Space ID", 1, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Register Bit Width", 1, 1, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Register Bit Offset", 1, 2, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Access Size", 1, 3, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Address", 8, 4, L"0x%lx", NULL, NULL, NULL, NULL} +}; + +/** + This function indents and traces the GAS structure as described by the GasParser. + + @param [in] Ptr Pointer to the start of the buffer. + @param [in] Indent Number of spaces to indent the output. + @param [in] Length Length of the GAS structure buffer. + + @retval Number of bytes parsed. +**/ +UINT32 +EFIAPI +DumpGasStruct ( + IN UINT8* Ptr, + IN UINT32 Indent, + IN UINT32 Length + ) +{ + Print (L"\n"); + return ParseAcpi ( + TRUE, + Indent, + NULL, + Ptr, + Length, + PARSER_PARAMS (GasParser) + ); +} + +/** + This function traces the GAS structure as described by the GasParser. + + @param [in] Format Optional format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +VOID +EFIAPI +DumpGas ( + IN CONST CHAR16* Format OPTIONAL, + IN UINT8* Ptr + ) +{ + DumpGasStruct (Ptr, 2, sizeof (EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE)); +} + +/** + This function traces the ACPI header as described by the AcpiHeaderParser. + + @param [in] Ptr Pointer to the start of the buffer. + + @retval Number of bytes parsed. +**/ +UINT32 +EFIAPI +DumpAcpiHeader ( + IN UINT8* Ptr + ) +{ + return ParseAcpi ( + TRUE, + 0, + "ACPI Table Header", + Ptr, + sizeof (EFI_ACPI_DESCRIPTION_HEADER), + PARSER_PARAMS (AcpiHeaderParser) + ); +} + +/** + This function parses the ACPI header as described by the AcpiHeaderParser. + + This function optionally returns the signature, length and revision of the + ACPI table. + + @param [in] Ptr Pointer to the start of the buffer. + @param [out] Signature Gets location of the ACPI table signature. + @param [out] Length Gets location of the length of the ACPI table. + @param [out] Revision Gets location of the revision of the ACPI table. + + @retval Number of bytes parsed. +**/ +UINT32 +EFIAPI +ParseAcpiHeader ( + IN UINT8* Ptr, + OUT CONST UINT32** Signature, + OUT CONST UINT32** Length, + OUT CONST UINT8** Revision + ) +{ + UINT32 BytesParsed; + + BytesParsed = ParseAcpi ( + FALSE, + 0, + NULL, + Ptr, + sizeof (EFI_ACPI_DESCRIPTION_HEADER), + PARSER_PARAMS (AcpiHeaderParser) + ); + + *Signature = AcpiHdrInfo.Signature; + *Length = AcpiHdrInfo.Length; + *Revision = AcpiHdrInfo.Revision; + + return BytesParsed; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h new file mode 100644 index 00000000..19d866d0 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h @@ -0,0 +1,899 @@ +/** @file + Header file for ACPI parser + + Copyright (c) 2016 - 2020, Arm Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef ACPIPARSER_H_ +#define ACPIPARSER_H_ + +#define OUTPUT_FIELD_COLUMN_WIDTH 36 + +/// The RSDP table signature is "RSD PTR " (8 bytes) +/// However The signature for ACPI tables is 4 bytes. +/// To work around this oddity define a signature type +/// that allows us to process the log options. +#define RSDP_TABLE_INFO SIGNATURE_32('R', 'S', 'D', 'P') + +/** + This function increments the ACPI table error counter. +**/ +VOID +EFIAPI +IncrementErrorCount ( + VOID + ); + +/** + This function increments the ACPI table warning counter. +**/ +VOID +EFIAPI +IncrementWarningCount ( + VOID + ); + +/** + This function verifies the ACPI table checksum. + + This function verifies the checksum for the ACPI table and optionally + prints the status. + + @param [in] Log If TRUE log the status of the checksum. + @param [in] Ptr Pointer to the start of the table buffer. + @param [in] Length The length of the buffer. + + @retval TRUE The checksum is OK. + @retval FALSE The checksum failed. +**/ +BOOLEAN +EFIAPI +VerifyChecksum ( + IN BOOLEAN Log, + IN UINT8* Ptr, + IN UINT32 Length + ); + +/** + This function performs a raw data dump of the ACPI table. + + @param [in] Ptr Pointer to the start of the table buffer. + @param [in] Length The length of the buffer. +**/ +VOID +EFIAPI +DumpRaw ( + IN UINT8* Ptr, + IN UINT32 Length + ); + +/** + This function traces 1 byte of datum as specified in the format string. + + @param [in] Format The format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +VOID +EFIAPI +DumpUint8 ( + IN CONST CHAR16* Format, + IN UINT8* Ptr + ); + +/** + This function traces 2 bytes of data as specified in the format string. + + @param [in] Format The format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +VOID +EFIAPI +DumpUint16 ( + IN CONST CHAR16* Format, + IN UINT8* Ptr + ); + +/** + This function traces 4 bytes of data as specified in the format string. + + @param [in] Format The format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +VOID +EFIAPI +DumpUint32 ( + IN CONST CHAR16* Format, + IN UINT8* Ptr + ); + +/** + This function traces 8 bytes of data as specified by the format string. + + @param [in] Format The format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +VOID +EFIAPI +DumpUint64 ( + IN CONST CHAR16* Format, + IN UINT8* Ptr + ); + +/** + This function traces 3 characters which can be optionally + formated using the format string if specified. + + If no format string is specified the Format must be NULL. + + @param [in] Format Optional format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +VOID +EFIAPI +Dump3Chars ( + IN CONST CHAR16* Format OPTIONAL, + IN UINT8* Ptr + ); + +/** + This function traces 4 characters which can be optionally + formated using the format string if specified. + + If no format string is specified the Format must be NULL. + + @param [in] Format Optional format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +VOID +EFIAPI +Dump4Chars ( + IN CONST CHAR16* Format OPTIONAL, + IN UINT8* Ptr + ); + +/** + This function traces 6 characters which can be optionally + formated using the format string if specified. + + If no format string is specified the Format must be NULL. + + @param [in] Format Optional format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +VOID +EFIAPI +Dump6Chars ( + IN CONST CHAR16* Format OPTIONAL, + IN UINT8* Ptr + ); + +/** + This function traces 8 characters which can be optionally + formated using the format string if specified. + + If no format string is specified the Format must be NULL. + + @param [in] Format Optional format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +VOID +EFIAPI +Dump8Chars ( + IN CONST CHAR16* Format OPTIONAL, + IN UINT8* Ptr + ); + +/** + This function traces 12 characters which can be optionally + formated using the format string if specified. + + If no format string is specified the Format must be NULL. + + @param [in] Format Optional format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +VOID +EFIAPI +Dump12Chars ( + IN CONST CHAR16* Format OPTIONAL, + IN UINT8* Ptr + ); + +/** + This function indents and prints the ACPI table Field Name. + + @param [in] Indent Number of spaces to add to the global table + indent. The global table indent is 0 by default; + however this value is updated on entry to the + ParseAcpi() by adding the indent value provided to + ParseAcpi() and restored back on exit. Therefore + the total indent in the output is dependent on from + where this function is called. + @param [in] FieldName Pointer to the Field Name. +**/ +VOID +EFIAPI +PrintFieldName ( + IN UINT32 Indent, + IN CONST CHAR16* FieldName + ); + +/** + This function pointer is the template for customizing the trace output + + @param [in] Format Format string for tracing the data as specified by + the 'Format' member of ACPI_PARSER. + @param [in] Ptr Pointer to the start of the buffer. +**/ +typedef VOID (EFIAPI *FNPTR_PRINT_FORMATTER)(CONST CHAR16* Format, UINT8* Ptr); + +/** + This function pointer is the template for validating an ACPI table field. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information as specified by + the 'Context' member of the ACPI_PARSER. + e.g. this could be a pointer to the ACPI table header. +**/ +typedef VOID (EFIAPI *FNPTR_FIELD_VALIDATOR)(UINT8* Ptr, VOID* Context); + +/** + The ACPI_PARSER structure describes the fields of an ACPI table and + provides means for the parser to interpret and trace appropriately. + + The first three members are populated based on information present in + in the ACPI table specifications. The remaining members describe how + the parser should report the field information, validate the field data + and/or update an external pointer to the field (ItemPtr). + + ParseAcpi() uses the format string specified by 'Format' for tracing + the field data. If the field is more complex and requires additional + processing for formatting and representation a print formatter function + can be specified in 'PrintFormatter'. + The PrintFormatter function may choose to use the format string + specified by 'Format' or use its own internal format string. + + The 'Format' and 'PrintFormatter' members allow flexibility for + representing the field data. +**/ +typedef struct AcpiParser { + + /// String describing the ACPI table field + /// (Field column from ACPI table spec) + CONST CHAR16* NameStr; + + /// The length of the field. + /// (Byte Length column from ACPI table spec) + UINT32 Length; + + /// The offset of the field from the start of the table. + /// (Byte Offset column from ACPI table spec) + UINT32 Offset; + + /// Optional Print() style format string for tracing the data. If not + /// used this must be set to NULL. + CONST CHAR16* Format; + + /// Optional pointer to a print formatter function which + /// is typically used to trace complex field information. + /// If not used this must be set to NULL. + /// The Format string is passed to the PrintFormatter function + /// but may be ignored by the implementation code. + FNPTR_PRINT_FORMATTER PrintFormatter; + + /// Optional pointer which may be set to request the parser to update + /// a pointer to the field data. If unused this must be set to NULL. + VOID** ItemPtr; + + /// Optional pointer to a field validator function. + /// The function should directly report any appropriate error or warning + /// and invoke the appropriate counter update function. + /// If not used this parameter must be set to NULL. + FNPTR_FIELD_VALIDATOR FieldValidator; + + /// Optional pointer to context specific information, + /// which the Field Validator function can use to determine + /// additional information about the ACPI table and make + /// decisions about the field being validated. + /// e.g. this could be a pointer to the ACPI table header + VOID* Context; +} ACPI_PARSER; + +/** + A structure used to store the pointers to the members of the + ACPI description header structure that was parsed. +**/ +typedef struct AcpiDescriptionHeaderInfo { + /// ACPI table signature + UINT32* Signature; + /// Length of the ACPI table + UINT32* Length; + /// Revision + UINT8* Revision; + /// Checksum + UINT8* Checksum; + /// OEM Id - length is 6 bytes + UINT8* OemId; + /// OEM table Id + UINT64* OemTableId; + /// OEM revision Id + UINT32* OemRevision; + /// Creator Id + UINT32* CreatorId; + /// Creator revision + UINT32* CreatorRevision; +} ACPI_DESCRIPTION_HEADER_INFO; + +/** + This function is used to parse an ACPI table buffer. + + The ACPI table buffer is parsed using the ACPI table parser information + specified by a pointer to an array of ACPI_PARSER elements. This parser + function iterates through each item on the ACPI_PARSER array and logs the + ACPI table fields. + + This function can optionally be used to parse ACPI tables and fetch specific + field values. The ItemPtr member of the ACPI_PARSER structure (where used) + is updated by this parser function to point to the selected field data + (e.g. useful for variable length nested fields). + + @param [in] Trace Trace the ACPI fields TRUE else only parse the + table. + @param [in] Indent Number of spaces to indent the output. + @param [in] AsciiName Optional pointer to an ASCII string that describes + the table being parsed. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] Length Length of the buffer pointed by Ptr. + @param [in] Parser Pointer to an array of ACPI_PARSER structure that + describes the table being parsed. + @param [in] ParserItems Number of items in the ACPI_PARSER array. + + @retval Number of bytes parsed. +**/ +UINT32 +EFIAPI +ParseAcpi ( + IN BOOLEAN Trace, + IN UINT32 Indent, + IN CONST CHAR8* AsciiName OPTIONAL, + IN UINT8* Ptr, + IN UINT32 Length, + IN CONST ACPI_PARSER* Parser, + IN UINT32 ParserItems + ); + +/** + This is a helper macro to pass parameters to the Parser functions. + + @param [in] Parser The name of the ACPI_PARSER array describing the + ACPI table fields. +**/ +#define PARSER_PARAMS(Parser) Parser, sizeof (Parser) / sizeof (Parser[0]) + +/** + This is a helper macro for describing the ACPI header fields. + + @param [out] Info Pointer to retrieve the ACPI table header information. +**/ +#define PARSE_ACPI_HEADER(Info) \ + { L"Signature", 4, 0, NULL, Dump4Chars, \ + (VOID**)&(Info)->Signature , NULL, NULL }, \ + { L"Length", 4, 4, L"%d", NULL, \ + (VOID**)&(Info)->Length, NULL, NULL }, \ + { L"Revision", 1, 8, L"%d", NULL, \ + (VOID**)&(Info)->Revision, NULL, NULL }, \ + { L"Checksum", 1, 9, L"0x%X", NULL, \ + (VOID**)&(Info)->Checksum, NULL, NULL }, \ + { L"Oem ID", 6, 10, NULL, Dump6Chars, \ + (VOID**)&(Info)->OemId, NULL, NULL }, \ + { L"Oem Table ID", 8, 16, NULL, Dump8Chars, \ + (VOID**)&(Info)->OemTableId, NULL, NULL }, \ + { L"Oem Revision", 4, 24, L"0x%X", NULL, \ + (VOID**)&(Info)->OemRevision, NULL, NULL }, \ + { L"Creator ID", 4, 28, NULL, Dump4Chars, \ + (VOID**)&(Info)->CreatorId, NULL, NULL }, \ + { L"Creator Revision", 4, 32, L"0x%X", NULL, \ + (VOID**)&(Info)->CreatorRevision, NULL, NULL } + +/** + This function indents and traces the GAS structure as described by the GasParser. + + @param [in] Ptr Pointer to the start of the buffer. + @param [in] Indent Number of spaces to indent the output. + @param [in] Length Length of the GAS structure buffer. + + @retval Number of bytes parsed. +**/ +UINT32 +EFIAPI +DumpGasStruct ( + IN UINT8* Ptr, + IN UINT32 Indent, + IN UINT32 Length + ); + +/** + This function traces the GAS structure as described by the GasParser. + + @param [in] Format Optional format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +VOID +EFIAPI +DumpGas ( + IN CONST CHAR16* Format OPTIONAL, + IN UINT8* Ptr + ); + +/** + This function traces the ACPI header as described by the AcpiHeaderParser. + + @param [in] Ptr Pointer to the start of the buffer. + + @retval Number of bytes parsed. +**/ +UINT32 +EFIAPI +DumpAcpiHeader ( + IN UINT8* Ptr + ); + +/** + This function parses the ACPI header as described by the AcpiHeaderParser. + + This function optionally returns the Signature, Length and revision of the + ACPI table. + + @param [in] Ptr Pointer to the start of the buffer. + @param [out] Signature Gets location of the ACPI table signature. + @param [out] Length Gets location of the length of the ACPI table. + @param [out] Revision Gets location of the revision of the ACPI table. + + @retval Number of bytes parsed. +**/ +UINT32 +EFIAPI +ParseAcpiHeader ( + IN UINT8* Ptr, + OUT CONST UINT32** Signature, + OUT CONST UINT32** Length, + OUT CONST UINT8** Revision + ); + +/** + This function parses the ACPI AEST table. + When trace is enabled this function parses the AEST table and + traces the ACPI table fields. + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiAest ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ); + +/** + This function parses the ACPI BGRT table. + When trace is enabled this function parses the BGRT table and + traces the ACPI table fields. + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiBgrt ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ); + +/** + This function parses the ACPI DBG2 table. + When trace is enabled this function parses the DBG2 table and + traces the ACPI table fields. + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiDbg2 ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ); + +/** + This function parses the ACPI DSDT table. + When trace is enabled this function parses the DSDT table and + traces the ACPI table fields. + For the DSDT table only the ACPI header fields are parsed and + traced. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiDsdt ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ); + +/** + This function parses the ACPI FACS table. + When trace is enabled this function parses the FACS table and + traces the ACPI table fields. + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiFacs ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ); + +/** + This function parses the ACPI FADT table. + This function parses the FADT table and optionally traces the ACPI + table fields. + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiFadt ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ); + +/** + This function parses the ACPI GTDT table. + When trace is enabled this function parses the GTDT table and + traces the ACPI table fields. + + This function also parses the following platform timer structures: + - GT Block timer + - Watchdog timer + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiGtdt ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ); + +/** + This function parses the ACPI HMAT table. + When trace is enabled this function parses the HMAT table and + traces the ACPI table fields. + + This function parses the following HMAT structures: + - Memory Proximity Domain Attributes Structure (Type 0) + - System Locality Latency and Bandwidth Info Structure (Type 1) + - Memory Side Cache Info structure (Type 2) + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiHmat ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ); + +/** + This function parses the ACPI IORT table. + When trace is enabled this function parses the IORT table and + traces the ACPI fields. + + This function also parses the following nodes: + - ITS Group + - Named Component + - Root Complex + - SMMUv1/2 + - SMMUv3 + - PMCG + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiIort ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ); + +/** + This function parses the ACPI MADT table. + When trace is enabled this function parses the MADT table and + traces the ACPI table fields. + + This function currently parses the following Interrupt Controller + Structures: + - GICC + - GICD + - GIC MSI Frame + - GICR + - GIC ITS + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiMadt ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ); + +/** + This function parses the ACPI MCFG table. + When trace is enabled this function parses the MCFG table and + traces the ACPI table fields. + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiMcfg ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ); + +/** + This function parses the ACPI PCCT table including its sub-structures + of type 0 through 4. + When trace is enabled this function parses the PCCT table and + traces the ACPI table fields. + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiPcct ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ); + +/** + This function parses the ACPI PPTT table. + When trace is enabled this function parses the PPTT table and + traces the ACPI table fields. + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiPptt ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ); + +/** + This function parses the ACPI RSDP table. + + This function invokes the parser for the XSDT table. + * Note - This function does not support parsing of RSDT table. + + This function also performs a RAW dump of the ACPI table and + validates the checksum. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiRsdp ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ); + +/** + This function parses the ACPI SLIT table. + When trace is enabled this function parses the SLIT table and + traces the ACPI table fields. + + This function also validates System Localities for the following: + - Diagonal elements have a normalized value of 10 + - Relative distance from System Locality at i*N+j is same as + j*N+i + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiSlit ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ); + +/** + This function parses the ACPI SPCR table. + When trace is enabled this function parses the SPCR table and + traces the ACPI table fields. + + This function also performs validations of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiSpcr ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ); + +/** + This function parses the ACPI SRAT table. + When trace is enabled this function parses the SRAT table and + traces the ACPI table fields. + + This function parses the following Resource Allocation Structures: + - Processor Local APIC/SAPIC Affinity Structure + - Memory Affinity Structure + - Processor Local x2APIC Affinity Structure + - GICC Affinity Structure + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiSrat ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ); + +/** + This function parses the ACPI SSDT table. + When trace is enabled this function parses the SSDT table and + traces the ACPI table fields. + For the SSDT table only the ACPI header fields are + parsed and traced. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiSsdt ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ); + +/** + This function parses the ACPI XSDT table + and optionally traces the ACPI table fields. + + This function also performs validation of the XSDT table. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiXsdt ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ); + +#endif // ACPIPARSER_H_ diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiTableParser.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiTableParser.c new file mode 100644 index 00000000..d081eb86 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiTableParser.c @@ -0,0 +1,251 @@ +/** @file + ACPI table parser + + Copyright (c) 2016 - 2020, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Glossary: + - Sbbr or SBBR - Server Base Boot Requirements + + @par Reference(s): + - Arm Server Base Boot Requirements 1.2, September 2019 +**/ + +#include +#include +#include +#include "AcpiParser.h" +#include "AcpiTableParser.h" +#include "AcpiView.h" +#include "AcpiViewConfig.h" + +#if defined(MDE_CPU_ARM) || defined (MDE_CPU_AARCH64) +#include "Arm/SbbrValidator.h" +#endif + +/** + A list of registered ACPI table parsers. +**/ +STATIC ACPI_TABLE_PARSER mTableParserList[MAX_ACPI_TABLE_PARSERS]; + +/** + Register the ACPI table Parser + + This function registers the ACPI table parser. + + @param [in] Signature The ACPI table signature. + @param [in] ParserProc The ACPI table parser. + + @retval EFI_SUCCESS The parser is registered. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_ALREADY_STARTED The parser for the Table + was already registered. + @retval EFI_OUT_OF_RESOURCES No space to register the + parser. +**/ +EFI_STATUS +EFIAPI +RegisterParser ( + IN UINT32 Signature, + IN PARSE_ACPI_TABLE_PROC ParserProc + ) +{ + UINT32 Index; + + if ((ParserProc == NULL) || (Signature == ACPI_PARSER_SIGNATURE_NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Search if a parser is already installed + for (Index = 0; + Index < (sizeof (mTableParserList) / sizeof (mTableParserList[0])); + Index++) + { + if (Signature == mTableParserList[Index].Signature) { + if (mTableParserList[Index].Parser != NULL) { + return EFI_ALREADY_STARTED; + } + } + } + + // Find the first free slot and register the parser + for (Index = 0; + Index < (sizeof (mTableParserList) / sizeof (mTableParserList[0])); + Index++) + { + if (mTableParserList[Index].Signature == ACPI_PARSER_SIGNATURE_NULL) { + mTableParserList[Index].Signature = Signature; + mTableParserList[Index].Parser = ParserProc; + return EFI_SUCCESS; + } + } + + // No free slot found + return EFI_OUT_OF_RESOURCES; +} + +/** + Deregister the ACPI table Parser + + This function deregisters the ACPI table parser. + + @param [in] Signature The ACPI table signature. + + @retval EFI_SUCCESS The parser was deregistered. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_NOT_FOUND A registered parser was not found. +**/ +EFI_STATUS +EFIAPI +DeregisterParser ( + IN UINT32 Signature + ) +{ + UINT32 Index; + + if (Signature == ACPI_PARSER_SIGNATURE_NULL) { + return EFI_INVALID_PARAMETER; + } + + for (Index = 0; + Index < (sizeof (mTableParserList) / sizeof (mTableParserList[0])); + Index++) + { + if (Signature == mTableParserList[Index].Signature) { + mTableParserList[Index].Signature = ACPI_PARSER_SIGNATURE_NULL; + mTableParserList[Index].Parser = NULL; + return EFI_SUCCESS; + } + } + + // No matching registered parser found. + return EFI_NOT_FOUND; +} + +/** + Get the ACPI table Parser + + This function returns the ACPI table parser proc from the list of + registered parsers. + + @param [in] Signature The ACPI table signature. + @param [out] ParserProc Pointer to a ACPI table parser proc. + + @retval EFI_SUCCESS The parser was returned successfully. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_NOT_FOUND A registered parser was not found. +**/ +EFI_STATUS +EFIAPI +GetParser ( + IN UINT32 Signature, + OUT PARSE_ACPI_TABLE_PROC * ParserProc + ) +{ + UINT32 Index; + + if ((ParserProc == NULL) || (Signature == ACPI_PARSER_SIGNATURE_NULL)) { + return EFI_INVALID_PARAMETER; + } + + for (Index = 0; + Index < (sizeof (mTableParserList) / sizeof (mTableParserList[0])); + Index++) + { + if (Signature == mTableParserList[Index].Signature) { + *ParserProc = mTableParserList[Index].Parser; + return EFI_SUCCESS; + } + } + + // No matching registered parser found. + return EFI_NOT_FOUND; +} + +/** + This function processes the ACPI tables. + This function calls ProcessTableReportOptions() to list the ACPI + tables, perform binary dump of the tables and determine if the + ACPI fields should be traced. + + This function also invokes the parser for the ACPI tables. + + This function also performs a RAW dump of the ACPI table including + the unknown/unparsed ACPI tables and validates the checksum. + + @param [in] Ptr Pointer to the start of the ACPI + table data buffer. +**/ +VOID +EFIAPI +ProcessAcpiTable ( + IN UINT8* Ptr + ) +{ + EFI_STATUS Status; + BOOLEAN Trace; + CONST UINT32* AcpiTableSignature; + CONST UINT32* AcpiTableLength; + CONST UINT8* AcpiTableRevision; + CONST UINT8* SignaturePtr; + PARSE_ACPI_TABLE_PROC ParserProc; + + ParseAcpiHeader ( + Ptr, + &AcpiTableSignature, + &AcpiTableLength, + &AcpiTableRevision + ); + + Trace = ProcessTableReportOptions ( + *AcpiTableSignature, + Ptr, + *AcpiTableLength + ); + + if (Trace) { + DumpRaw (Ptr, *AcpiTableLength); + + // Do not process the ACPI table any further if the table length read + // is invalid. The ACPI table should at least contain the table header. + if (*AcpiTableLength < sizeof (EFI_ACPI_DESCRIPTION_HEADER)) { + SignaturePtr = (CONST UINT8*)AcpiTableSignature; + IncrementErrorCount (); + Print ( + L"ERROR: Invalid %c%c%c%c table length. Length = %d\n", + SignaturePtr[0], + SignaturePtr[1], + SignaturePtr[2], + SignaturePtr[3], + *AcpiTableLength + ); + return; + } + + if (GetConsistencyChecking ()) { + VerifyChecksum (TRUE, Ptr, *AcpiTableLength); + } + } + +#if defined(MDE_CPU_ARM) || defined (MDE_CPU_AARCH64) + if (GetMandatoryTableValidate ()) { + ArmSbbrIncrementTableCount (*AcpiTableSignature); + } +#endif + + Status = GetParser (*AcpiTableSignature, &ParserProc); + if (EFI_ERROR (Status)) { + // No registered parser found, do default handling. + if (Trace) { + DumpAcpiHeader (Ptr); + } + return; + } + + ParserProc ( + Trace, + Ptr, + *AcpiTableLength, + *AcpiTableRevision + ); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiTableParser.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiTableParser.h new file mode 100644 index 00000000..acf93f9f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiTableParser.h @@ -0,0 +1,127 @@ +/** @file + Header file for ACPI table parser + + Copyright (c) 2016 - 2020, Arm Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef ACPITABLEPARSER_H_ +#define ACPITABLEPARSER_H_ + +/** + The maximum number of ACPI table parsers. +*/ +#define MAX_ACPI_TABLE_PARSERS 32 + +/** An invalid/NULL signature value. +*/ +#define ACPI_PARSER_SIGNATURE_NULL 0 + +/** + A function that parses the ACPI table. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +typedef +VOID +(EFIAPI * PARSE_ACPI_TABLE_PROC) ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ); + +/** + The ACPI table parser information +**/ +typedef struct AcpiTableParser { + /// ACPI table signature + UINT32 Signature; + + /// The ACPI table parser function. + PARSE_ACPI_TABLE_PROC Parser; +} ACPI_TABLE_PARSER; + +/** + Register the ACPI table Parser + + This function registers the ACPI table parser. + + @param [in] Signature The ACPI table signature. + @param [in] ParserProc The ACPI table parser. + + @retval EFI_SUCCESS The parser is registered. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_ALREADY_STARTED The parser for the Table + was already registered. + @retval EFI_OUT_OF_RESOURCES No space to register the + parser. +**/ +EFI_STATUS +EFIAPI +RegisterParser ( + IN UINT32 Signature, + IN PARSE_ACPI_TABLE_PROC ParserProc + ); + +/** + Deregister the ACPI table Parser + + This function deregisters the ACPI table parser. + + @param [in] Signature The ACPI table signature. + + @retval EFI_SUCCESS The parser was deregistered. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_NOT_FOUND A registered parser was not found. +**/ +EFI_STATUS +EFIAPI +DeregisterParser ( + IN UINT32 Signature + ); + +/** + This function processes the ACPI tables. + This function calls ProcessTableReportOptions() to list the ACPI + tables, perform binary dump of the tables and determine if the + ACPI fields should be traced. + + This function also invokes the parser for the ACPI tables. + + This function also performs a RAW dump of the ACPI table including + the unknown/unparsed ACPI tables and validates the checksum. + + @param [in] Ptr Pointer to the start of the ACPI + table data buffer. +**/ +VOID +EFIAPI +ProcessAcpiTable ( + IN UINT8* Ptr + ); + +/** + Get the ACPI table Parser + + This function returns the ACPI table parser proc from the list of + registered parsers. + + @param [in] Signature The ACPI table signature. + @param [out] ParserProc Pointer to a ACPI table parser proc. + + @retval EFI_SUCCESS The parser was returned successfully. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_NOT_FOUND A registered parser was not found. +**/ +EFI_STATUS +EFIAPI +GetParser ( + IN UINT32 Signature, + OUT PARSE_ACPI_TABLE_PROC * ParserProc + ); + +#endif // ACPITABLEPARSER_H_ diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiView.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiView.c new file mode 100644 index 00000000..9d39d52e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiView.c @@ -0,0 +1,324 @@ +/** @file + + Copyright (c) 2016 - 2020, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Glossary: + - Sbbr or SBBR - Server Base Boot Requirements + + @par Reference(s): + - Arm Server Base Boot Requirements 1.2, September 2019 +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "AcpiParser.h" +#include "AcpiTableParser.h" +#include "AcpiView.h" +#include "AcpiViewConfig.h" + +#if defined(MDE_CPU_ARM) || defined (MDE_CPU_AARCH64) +#include "Arm/SbbrValidator.h" +#endif + +STATIC UINT32 mTableCount; +STATIC UINT32 mBinTableCount; + +/** + This function dumps the ACPI table to a file. + + @param [in] Ptr Pointer to the ACPI table data. + @param [in] Length The length of the ACPI table. + + @retval TRUE Success. + @retval FALSE Failure. +**/ +STATIC +BOOLEAN +DumpAcpiTableToFile ( + IN CONST UINT8* Ptr, + IN CONST UINTN Length + ) +{ + CHAR16 FileNameBuffer[MAX_FILE_NAME_LEN]; + UINTN TransferBytes; + SELECTED_ACPI_TABLE *SelectedTable; + + GetSelectedAcpiTable (&SelectedTable); + + UnicodeSPrint ( + FileNameBuffer, + sizeof (FileNameBuffer), + L".\\%s%04d.bin", + SelectedTable->Name, + mBinTableCount++ + ); + + Print (L"Dumping ACPI table to : %s ... ", FileNameBuffer); + + TransferBytes = ShellDumpBufferToFile (FileNameBuffer, Ptr, Length); + return (Length == TransferBytes); +} + +/** + This function processes the table reporting options for the ACPI table. + + @param [in] Signature The ACPI table Signature. + @param [in] TablePtr Pointer to the ACPI table data. + @param [in] Length The length fo the ACPI table. + + @retval Returns TRUE if the ACPI table should be traced. +**/ +BOOLEAN +ProcessTableReportOptions ( + IN CONST UINT32 Signature, + IN CONST UINT8* TablePtr, + IN CONST UINT32 Length + ) +{ + UINTN OriginalAttribute; + UINT8 *SignaturePtr; + BOOLEAN Log; + BOOLEAN HighLight; + SELECTED_ACPI_TABLE *SelectedTable; + + // + // set local variables to suppress incorrect compiler/analyzer warnings + // + OriginalAttribute = 0; + SignaturePtr = (UINT8*)(UINTN)&Signature; + Log = FALSE; + HighLight = GetColourHighlighting (); + GetSelectedAcpiTable (&SelectedTable); + + switch (GetReportOption ()) { + case ReportAll: + Log = TRUE; + break; + case ReportSelected: + if (Signature == SelectedTable->Type) { + Log = TRUE; + SelectedTable->Found = TRUE; + } + break; + case ReportTableList: + if (mTableCount == 0) { + if (HighLight) { + OriginalAttribute = gST->ConOut->Mode->Attribute; + gST->ConOut->SetAttribute ( + gST->ConOut, + EFI_TEXT_ATTR(EFI_CYAN, + ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)) + ); + } + Print (L"\nInstalled Table(s):\n"); + if (HighLight) { + gST->ConOut->SetAttribute (gST->ConOut, OriginalAttribute); + } + } + Print ( + L"\t%4d. %c%c%c%c\n", + ++mTableCount, + SignaturePtr[0], + SignaturePtr[1], + SignaturePtr[2], + SignaturePtr[3] + ); + break; + case ReportDumpBinFile: + if (Signature == SelectedTable->Type) { + SelectedTable->Found = TRUE; + DumpAcpiTableToFile (TablePtr, Length); + } + break; + case ReportMax: + // We should never be here. + // This case is only present to prevent compiler warning. + break; + } // switch + + if (Log) { + if (HighLight) { + OriginalAttribute = gST->ConOut->Mode->Attribute; + gST->ConOut->SetAttribute ( + gST->ConOut, + EFI_TEXT_ATTR(EFI_LIGHTBLUE, + ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)) + ); + } + Print ( + L"\n\n --------------- %c%c%c%c Table --------------- \n\n", + SignaturePtr[0], + SignaturePtr[1], + SignaturePtr[2], + SignaturePtr[3] + ); + if (HighLight) { + gST->ConOut->SetAttribute (gST->ConOut, OriginalAttribute); + } + } + + return Log; +} + + + +/** + This function iterates the configuration table entries in the + system table, retrieves the RSDP pointer and starts parsing the ACPI tables. + + @param [in] SystemTable Pointer to the EFI system table. + + @retval Returns EFI_NOT_FOUND if the RSDP pointer is not found. + Returns EFI_UNSUPPORTED if the RSDP version is less than 2. + Returns EFI_SUCCESS if successful. +**/ +EFI_STATUS +EFIAPI +AcpiView ( + IN EFI_SYSTEM_TABLE* SystemTable + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_CONFIGURATION_TABLE* EfiConfigurationTable; + BOOLEAN FoundAcpiTable; + UINTN OriginalAttribute; + UINTN PrintAttribute; + EREPORT_OPTION ReportOption; + UINT8* RsdpPtr; + UINT32 RsdpLength; + UINT8 RsdpRevision; + PARSE_ACPI_TABLE_PROC RsdpParserProc; + BOOLEAN Trace; + SELECTED_ACPI_TABLE *SelectedTable; + + // + // set local variables to suppress incorrect compiler/analyzer warnings + // + EfiConfigurationTable = NULL; + OriginalAttribute = 0; + + // Reset Table counts + mTableCount = 0; + mBinTableCount = 0; + + // Reset The error/warning counters + ResetErrorCount (); + ResetWarningCount (); + + // Retrieve the user selection of ACPI table to process + GetSelectedAcpiTable (&SelectedTable); + + // Search the table for an entry that matches the ACPI Table Guid + FoundAcpiTable = FALSE; + for (Index = 0; Index < SystemTable->NumberOfTableEntries; Index++) { + if (CompareGuid (&gEfiAcpiTableGuid, + &(SystemTable->ConfigurationTable[Index].VendorGuid))) { + EfiConfigurationTable = &SystemTable->ConfigurationTable[Index]; + FoundAcpiTable = TRUE; + break; + } + } + + if (FoundAcpiTable) { + RsdpPtr = (UINT8*)EfiConfigurationTable->VendorTable; + + // The RSDP revision is 1 byte starting at offset 15 + RsdpRevision = *(RsdpPtr + RSDP_REVISION_OFFSET); + + if (RsdpRevision < 2) { + Print ( + L"ERROR: RSDP version less than 2 is not supported.\n" + ); + return EFI_UNSUPPORTED; + } + +#if defined(MDE_CPU_ARM) || defined (MDE_CPU_AARCH64) + if (GetMandatoryTableValidate ()) { + ArmSbbrResetTableCounts (); + } +#endif + + // The RSDP length is 4 bytes starting at offset 20 + RsdpLength = *(UINT32*)(RsdpPtr + RSDP_LENGTH_OFFSET); + + Trace = ProcessTableReportOptions (RSDP_TABLE_INFO, RsdpPtr, RsdpLength); + + Status = GetParser (RSDP_TABLE_INFO, &RsdpParserProc); + if (EFI_ERROR (Status)) { + Print ( + L"ERROR: No registered parser found for RSDP.\n" + ); + return Status; + } + + RsdpParserProc ( + Trace, + RsdpPtr, + RsdpLength, + RsdpRevision + ); + + } else { + IncrementErrorCount (); + Print ( + L"ERROR: Failed to find ACPI Table Guid in System Configuration Table.\n" + ); + return EFI_NOT_FOUND; + } + +#if defined(MDE_CPU_ARM) || defined (MDE_CPU_AARCH64) + if (GetMandatoryTableValidate ()) { + ArmSbbrReqsValidate ((ARM_SBBR_VERSION)GetMandatoryTableSpec ()); + } +#endif + + ReportOption = GetReportOption (); + if (ReportTableList != ReportOption) { + if (((ReportSelected == ReportOption) || + (ReportDumpBinFile == ReportOption)) && + (!SelectedTable->Found)) { + Print (L"\nRequested ACPI Table not found.\n"); + } else if (GetConsistencyChecking () && + (ReportDumpBinFile != ReportOption)) { + OriginalAttribute = gST->ConOut->Mode->Attribute; + + Print (L"\nTable Statistics:\n"); + + if (GetColourHighlighting ()) { + PrintAttribute = (GetErrorCount () > 0) ? + EFI_TEXT_ATTR ( + EFI_RED, + ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4) + ) : + OriginalAttribute; + gST->ConOut->SetAttribute (gST->ConOut, PrintAttribute); + } + Print (L"\t%d Error(s)\n", GetErrorCount ()); + + if (GetColourHighlighting ()) { + PrintAttribute = (GetWarningCount () > 0) ? + EFI_TEXT_ATTR ( + EFI_RED, + ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4) + ) : + OriginalAttribute; + + gST->ConOut->SetAttribute (gST->ConOut, PrintAttribute); + } + Print (L"\t%d Warning(s)\n", GetWarningCount ()); + + if (GetColourHighlighting ()) { + gST->ConOut->SetAttribute (gST->ConOut, OriginalAttribute); + } + } + } + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiView.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiView.h new file mode 100644 index 00000000..7905f179 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiView.h @@ -0,0 +1,94 @@ +/** @file + Header file for AcpiView + + Copyright (c) 2016 - 2020, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef ACPIVIEW_H_ +#define ACPIVIEW_H_ + +/** + A macro to define the max file name length +**/ +#define MAX_FILE_NAME_LEN 128 + +/** + Offset to the RSDP revision from the start of the RSDP +**/ +#define RSDP_REVISION_OFFSET 15 + +/** + Offset to the RSDP length from the start of the RSDP +**/ +#define RSDP_LENGTH_OFFSET 20 + +/** + This function resets the ACPI table error counter to Zero. +**/ +VOID +ResetErrorCount ( + VOID + ); + +/** + This function returns the ACPI table error count. + + @retval Returns the count of errors detected in the ACPI tables. +**/ +UINT32 +GetErrorCount ( + VOID + ); + +/** + This function resets the ACPI table warning counter to Zero. +**/ +VOID +ResetWarningCount ( + VOID + ); + +/** + This function returns the ACPI table warning count. + + @retval Returns the count of warning detected in the ACPI tables. +**/ +UINT32 +GetWarningCount ( + VOID + ); + +/** + This function processes the table reporting options for the ACPI table. + + @param [in] Signature The ACPI table Signature. + @param [in] TablePtr Pointer to the ACPI table data. + @param [in] Length The length of the ACPI table. + + @retval Returns TRUE if the ACPI table should be traced. +**/ +BOOLEAN +ProcessTableReportOptions ( + IN CONST UINT32 Signature, + IN CONST UINT8* TablePtr, + IN CONST UINT32 Length + ); + +/** + This function iterates the configuration table entries in the + system table, retrieves the RSDP pointer and starts parsing the ACPI tables. + + @param [in] SystemTable Pointer to the EFI system table. + + @retval EFI_NOT_FOUND The RSDP pointer was not found. + @retval EFI_UNSUPPORTED The RSDP version was less than 2. + @retval EFI_SUCCESS The command was successful. +**/ +EFI_STATUS +EFIAPI +AcpiView ( + IN EFI_SYSTEM_TABLE* SystemTable + ); + +#endif // ACPIVIEW_H_ diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiViewConfig.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiViewConfig.c new file mode 100644 index 00000000..cf02dc61 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiViewConfig.c @@ -0,0 +1,246 @@ +/** @file + State and accessors for 'acpiview' configuration. + + Copyright (c) 2016 - 2020, ARM Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include + +#include "AcpiViewConfig.h" + +// Report variables +STATIC BOOLEAN mConsistencyCheck; +STATIC BOOLEAN mColourHighlighting; +STATIC EREPORT_OPTION mReportType; +STATIC BOOLEAN mMandatoryTableValidate; +STATIC UINTN mMandatoryTableSpec; + +// User selection of which ACPI table should be checked +SELECTED_ACPI_TABLE mSelectedAcpiTable; + +/** + Reset the AcpiView user configuration to defaults +**/ +VOID +EFIAPI +AcpiConfigSetDefaults ( + VOID + ) +{ + mReportType = ReportAll; + mSelectedAcpiTable.Type = 0; + mSelectedAcpiTable.Name = NULL; + mSelectedAcpiTable.Found = FALSE; + mConsistencyCheck = TRUE; + mMandatoryTableValidate = FALSE; + mMandatoryTableSpec = 0; +} + +/** + This function converts a string to ACPI table signature. + + @param [in] Str Pointer to the string to be converted to the + ACPI table signature. + + @retval The ACPI table signature. +**/ +STATIC +UINT32 +ConvertStrToAcpiSignature ( + IN CONST CHAR16 *Str + ) +{ + UINT8 Index; + CHAR8 Ptr[4]; + + ZeroMem (Ptr, sizeof (Ptr)); + Index = 0; + + // Convert to Upper case and convert to ASCII + while ((Index < 4) && (Str[Index] != 0)) { + if (Str[Index] >= L'a' && Str[Index] <= L'z') { + Ptr[Index] = (CHAR8)(Str[Index] - (L'a' - L'A')); + } else { + Ptr[Index] = (CHAR8)Str[Index]; + } + Index++; + } + return *(UINT32 *) Ptr; +} + +/** + This function selects an ACPI table in current context. + The string name of the table is converted into UINT32 + table signature. + + @param [in] TableName The name of the ACPI table to select. +**/ +VOID +EFIAPI +SelectAcpiTable ( + IN CONST CHAR16 *TableName + ) +{ + ASSERT (TableName != NULL); + + mSelectedAcpiTable.Name = TableName; + mSelectedAcpiTable.Type = ConvertStrToAcpiSignature (mSelectedAcpiTable.Name); +} + +/** + This function returns the selected ACPI table. + + @param [out] SelectedAcpiTable Pointer that will contain the returned struct. +**/ +VOID +EFIAPI +GetSelectedAcpiTable ( + OUT SELECTED_ACPI_TABLE **SelectedAcpiTable + ) +{ + *SelectedAcpiTable = &mSelectedAcpiTable; +} + +/** + This function returns the colour highlighting status. + + @retval TRUE Colour highlighting is enabled. +**/ +BOOLEAN +EFIAPI +GetColourHighlighting ( + VOID + ) +{ + return mColourHighlighting; +} + +/** + This function sets the colour highlighting status. + + @param [in] Highlight The highlight status. +**/ +VOID +EFIAPI +SetColourHighlighting ( + BOOLEAN Highlight + ) +{ + mColourHighlighting = Highlight; +} + +/** + This function returns the consistency checking status. + + @retval TRUE Consistency checking is enabled. +**/ +BOOLEAN +EFIAPI +GetConsistencyChecking ( + VOID + ) +{ + return mConsistencyCheck; +} + +/** + This function sets the consistency checking status. + + @param [in] ConsistencyChecking The consistency checking status. +**/ +VOID +EFIAPI +SetConsistencyChecking ( + BOOLEAN ConsistencyChecking + ) +{ + mConsistencyCheck = ConsistencyChecking; +} + +/** + This function returns the report options. + + @return The current report option. +**/ +EREPORT_OPTION +EFIAPI +GetReportOption ( + VOID + ) +{ + return mReportType; +} + +/** + This function sets the report options. + + @param [in] ReportType The report option to set. +**/ +VOID +EFIAPI +SetReportOption ( + EREPORT_OPTION ReportType + ) +{ + mReportType = ReportType; +} + +/** + This function returns the ACPI table requirements validation flag. + + @retval TRUE Check for mandatory table presence should be performed. +**/ +BOOLEAN +EFIAPI +GetMandatoryTableValidate ( + VOID + ) +{ + return mMandatoryTableValidate; +} + +/** + This function sets the ACPI table requirements validation flag. + + @param [in] Validate Enable/Disable ACPI table requirements validation. +**/ +VOID +EFIAPI +SetMandatoryTableValidate ( + BOOLEAN Validate + ) +{ + mMandatoryTableValidate = Validate; +} + +/** + This function returns the identifier of specification to validate ACPI table + requirements against. + + @return ID of specification listing mandatory tables. +**/ +UINTN +EFIAPI +GetMandatoryTableSpec ( + VOID + ) +{ + return mMandatoryTableSpec; +} + +/** + This function sets the identifier of specification to validate ACPI table + requirements against. + + @param [in] Spec ID of specification listing mandatory tables. +**/ +VOID +EFIAPI +SetMandatoryTableSpec ( + UINTN Spec + ) +{ + mMandatoryTableSpec = Spec; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiViewConfig.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiViewConfig.h new file mode 100644 index 00000000..d9173874 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiViewConfig.h @@ -0,0 +1,177 @@ +/** @file + Header file for 'acpiview' configuration. + + Copyright (c) 2016 - 2020, ARM Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef ACPI_VIEW_CONFIG_H_ +#define ACPI_VIEW_CONFIG_H_ + +/** + This function returns the colour highlighting status. + + @retval TRUE Colour highlighting is enabled. +**/ +BOOLEAN +EFIAPI +GetColourHighlighting ( + VOID + ); + +/** + This function sets the colour highlighting status. + + @param [in] Highlight The highlight status. +**/ +VOID +EFIAPI +SetColourHighlighting ( + BOOLEAN Highlight + ); + +/** + This function returns the consistency checking status. + + @retval TRUE Consistency checking is enabled. +**/ +BOOLEAN +EFIAPI +GetConsistencyChecking ( + VOID + ); + +/** + This function sets the consistency checking status. + + @param [in] ConsistencyChecking The consistency checking status. +**/ +VOID +EFIAPI +SetConsistencyChecking ( + BOOLEAN ConsistencyChecking + ); + +/** + This function returns the ACPI table requirements validation flag. + + @retval TRUE Check for mandatory table presence should be performed. +**/ +BOOLEAN +EFIAPI +GetMandatoryTableValidate ( + VOID + ); + +/** + This function sets the ACPI table requirements validation flag. + + @param [in] Validate Enable/Disable ACPI table requirements validation. +**/ +VOID +EFIAPI +SetMandatoryTableValidate ( + BOOLEAN Validate + ); + +/** + This function returns the identifier of specification to validate ACPI table + requirements against. + + @return ID of specification listing mandatory tables. +**/ +UINTN +EFIAPI +GetMandatoryTableSpec ( + VOID + ); + +/** + This function sets the identifier of specification to validate ACPI table + requirements against. + + @param [in] Spec ID of specification listing mandatory tables. +**/ +VOID +EFIAPI +SetMandatoryTableSpec ( + UINTN Spec + ); + +/** + The EREPORT_OPTION enum describes ACPI table Reporting options. +**/ +typedef enum { + ReportAll, ///< Report All tables. + ReportSelected, ///< Report Selected table. + ReportTableList, ///< Report List of tables. + ReportDumpBinFile, ///< Dump selected table to a file. + ReportMax, +} EREPORT_OPTION; + +/** + This function returns the report options. + + @return The current report option. +**/ +EREPORT_OPTION +EFIAPI +GetReportOption ( + VOID + ); + +/** + This function sets the report options. + + @param [in] ReportType The report option to set. +**/ +VOID +EFIAPI +SetReportOption ( + EREPORT_OPTION ReportType + ); + +/** + A structure holding the user selection detailing which + ACPI table is to be examined by the AcpiView code. +**/ +typedef struct { + UINT32 Type; ///< 32bit signature of the selected ACPI table. + CONST CHAR16* Name; ///< User friendly name of the selected ACPI table. + BOOLEAN Found; ///< The selected table has been found in the system. +} SELECTED_ACPI_TABLE; + +/** + This function returns the selected ACPI table. + + @param [out] SelectedAcpiTable Pointer that will contain the returned struct. +**/ +VOID +EFIAPI +GetSelectedAcpiTable ( + OUT SELECTED_ACPI_TABLE** SelectedAcpiTable + ); + +/** + This function selects an ACPI table in current context. + The string name of the table is converted into UINT32 + table signature. + + @param [in] TableName The name of the ACPI table to select. +**/ +VOID +EFIAPI +SelectAcpiTable ( + CONST CHAR16* TableName + ); + +/** + Reset the AcpiView user configuration to defaults. +**/ +VOID +EFIAPI +AcpiConfigSetDefaults ( + VOID + ); + +#endif // ACPI_VIEW_CONFIG_H_ diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Arm/SbbrValidator.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Arm/SbbrValidator.c new file mode 100644 index 00000000..f89ec016 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Arm/SbbrValidator.c @@ -0,0 +1,222 @@ +/** @file + Arm Server Base Boot Requirements ACPI table requirement validator. + + Copyright (c) 2020, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Glossary: + - Sbbr or SBBR - Server Base Boot Requirements + - Sbsa or SBSA - Server Base System Architecture + + @par Reference(s): + - Arm Server Base Boot Requirements 1.2, September 2019 + - Arm Server Base Boot Requirements 1.1, May 2018 + - Arm Server Base Boot Requirements 1.0, March 2016 + - Arm Server Base System Architecture 6.0 +**/ + +#include +#include +#include "AcpiParser.h" +#include "Arm/SbbrValidator.h" + +/** + SBBR specification version strings +**/ +STATIC CONST CHAR8* ArmSbbrVersions[ArmSbbrVersionMax] = { + "1.0", // ArmSbbrVersion_1_0 + "1.1", // ArmSbbrVersion_1_1 + "1.2" // ArmSbbrVersion_1_2 +}; + +/** + SBBR 1.0 mandatory ACPI tables +**/ +STATIC CONST UINT32 ArmSbbr10Mandatory[] = { + EFI_ACPI_6_3_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, + EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE, + EFI_ACPI_6_3_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, + EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE, + EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE, + EFI_ACPI_6_3_DEBUG_PORT_2_TABLE_SIGNATURE, + EFI_ACPI_6_3_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE +}; + +/** + SBBR 1.1 mandatory ACPI tables +**/ +STATIC CONST UINT32 ArmSbbr11Mandatory[] = { + EFI_ACPI_6_3_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, + EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE, + EFI_ACPI_6_3_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, + EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE, + EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE, + EFI_ACPI_6_3_DEBUG_PORT_2_TABLE_SIGNATURE, + EFI_ACPI_6_3_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE, + EFI_ACPI_6_3_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE +}; + +/** + SBBR 1.2 mandatory ACPI tables +**/ +STATIC CONST UINT32 ArmSbbr12Mandatory[] = { + EFI_ACPI_6_3_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, + EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE, + EFI_ACPI_6_3_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, + EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE, + EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE, + EFI_ACPI_6_3_DEBUG_PORT_2_TABLE_SIGNATURE, + EFI_ACPI_6_3_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE, + EFI_ACPI_6_3_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE, + EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_STRUCTURE_SIGNATURE +}; + +/** + Mandatory ACPI tables for every SBBR specification version. +**/ +STATIC CONST ACPI_SBBR_REQ ArmSbbrReqs[ArmSbbrVersionMax] = { + { ArmSbbr10Mandatory, ARRAY_SIZE (ArmSbbr10Mandatory) }, // SBBR v1.0 + { ArmSbbr11Mandatory, ARRAY_SIZE (ArmSbbr11Mandatory) }, // SBBR v1.1 + { ArmSbbr12Mandatory, ARRAY_SIZE (ArmSbbr12Mandatory) } // SBBR v1.2 +}; + +/** + Data structure to track instance counts for all ACPI tables which are + defined as 'mandatory' in any SBBR version. +**/ +STATIC ACPI_TABLE_COUNTER ArmSbbrTableCounts[] = { + {EFI_ACPI_6_3_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, 0}, + {EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE, 0}, + {EFI_ACPI_6_3_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, 0}, + {EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE, 0}, + {EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE, 0}, + {EFI_ACPI_6_3_DEBUG_PORT_2_TABLE_SIGNATURE, 0}, + {EFI_ACPI_6_3_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE, 0}, + {EFI_ACPI_6_3_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE, 0}, + {EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_STRUCTURE_SIGNATURE, 0} +}; + +/** + Reset the platform ACPI table instance count for all SBBR-mandatory tables. +**/ +VOID +EFIAPI +ArmSbbrResetTableCounts ( + VOID + ) +{ + UINT32 Table; + + for (Table = 0; Table < ARRAY_SIZE (ArmSbbrTableCounts); Table++) { + ArmSbbrTableCounts[Table].Count = 0; + } +} + +/** + Increment instance count for SBBR-mandatory ACPI table with the given + signature. + + @param [in] Signature ACPI table signature. + + @retval TRUE Count incremented successfully. + @retval FALSE Table with the input signature not found. +**/ +BOOLEAN +EFIAPI +ArmSbbrIncrementTableCount ( + UINT32 Signature + ) +{ + UINT32 Table; + + for (Table = 0; Table < ARRAY_SIZE (ArmSbbrTableCounts); Table++) { + if (Signature == ArmSbbrTableCounts[Table].Signature) { + ArmSbbrTableCounts[Table].Count++; + return TRUE; + } + } + + return FALSE; +} + +/** + Validate that all ACPI tables required by the given SBBR specification + version are installed on the platform. + + @param [in] Version SBBR spec version to validate against. + + @retval EFI_SUCCESS All required tables are present. + @retval EFI_INVALID_PARAMETER Invalid SBBR version. + @retval EFI_NOT_FOUND One or more mandatory tables are missing. + @retval EFI_UNSUPPORTED Mandatory ACPI table does not have its + instance count tracked. +**/ +EFI_STATUS +EFIAPI +ArmSbbrReqsValidate ( + ARM_SBBR_VERSION Version + ) +{ + UINT32 Table; + UINT32 Index; + UINT32 MandatoryTable; + CONST UINT8* SignaturePtr; + BOOLEAN IsArmSbbrViolated; + + if (Version >= ArmSbbrVersionMax) { + return EFI_INVALID_PARAMETER; + } + + IsArmSbbrViolated = FALSE; + + // Go through the list of mandatory tables for the input SBBR version + for (Table = 0; Table < ArmSbbrReqs[Version].TableCount; Table++) { + MandatoryTable = ArmSbbrReqs[Version].Tables[Table]; + SignaturePtr = (CONST UINT8*)(UINTN)&MandatoryTable; + + // Locate the instance count for the table with the given signature + Index = 0; + while ((Index < ARRAY_SIZE (ArmSbbrTableCounts)) && + (ArmSbbrTableCounts[Index].Signature != MandatoryTable)) { + Index++; + } + + if (Index >= ARRAY_SIZE (ArmSbbrTableCounts)) { + IncrementErrorCount (); + Print ( + L"\nERROR: SBBR v%a: Mandatory %c%c%c%c table's instance count not " \ + L"found\n", + ArmSbbrVersions[Version], + SignaturePtr[0], + SignaturePtr[1], + SignaturePtr[2], + SignaturePtr[3] + ); + return EFI_UNSUPPORTED; + } + + if (ArmSbbrTableCounts[Index].Count == 0) { + IsArmSbbrViolated = TRUE; + IncrementErrorCount (); + Print ( + L"\nERROR: SBBR v%a: Mandatory %c%c%c%c table is missing", + ArmSbbrVersions[Version], + SignaturePtr[0], + SignaturePtr[1], + SignaturePtr[2], + SignaturePtr[3] + ); + } + } + + if (!IsArmSbbrViolated) { + Print ( + L"\nINFO: SBBR v%a: All mandatory ACPI tables are installed", + ArmSbbrVersions[Version] + ); + } + + Print (L"\n"); + + return IsArmSbbrViolated ? EFI_NOT_FOUND : EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Arm/SbbrValidator.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Arm/SbbrValidator.h new file mode 100644 index 00000000..36ab73db --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Arm/SbbrValidator.h @@ -0,0 +1,91 @@ +/** @file + Header file for SbbrValidator.c + + Copyright (c) 2020, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Glossary: + - Sbbr or SBBR - Server Base Boot Requirements + - Sbsa or SBSA - Server Base System Architecture + + @par Reference(s): + - Arm Server Base Boot Requirements 1.2, September 2019 + - Arm Server Base Boot Requirements 1.1, May 2018 + - Arm Server Base Boot Requirements 1.0, March 2016 + - Arm Server Base System Architecture 6.0 +**/ + +#ifndef SBBR_VALIDATOR_H_ +#define SBBR_VALIDATOR_H_ + +#include + +/** + Arm SBBR specification versions. +**/ +typedef enum { + ArmSbbrVersion_1_0 = 0, + ArmSbbrVersion_1_1 = 1, + ArmSbbrVersion_1_2 = 2, + ArmSbbrVersionMax = 3 +} ARM_SBBR_VERSION; + +/** + The ACPI table instance counter. +**/ +typedef struct AcpiTableCounter { + CONST UINT32 Signature; /// ACPI table signature + UINT32 Count; /// Instance count +} ACPI_TABLE_COUNTER; + +/** + ACPI table SBBR requirements. +**/ +typedef struct AcpiSbbrReq { + CONST UINT32* Tables; /// List of required tables + CONST UINT32 TableCount; /// Number of elements in Tables +} ACPI_SBBR_REQ; + +/** + Reset the platform ACPI table instance count for all SBBR-mandatory tables. +**/ +VOID +EFIAPI +ArmSbbrResetTableCounts ( + VOID + ); + +/** + Increment instance count for SBBR-mandatory ACPI table with the given + signature. + + @param [in] Signature ACPI table signature. + + @retval TRUE Count incremented successfully. + @retval FALSE Table with the input signature not found. +**/ +BOOLEAN +EFIAPI +ArmSbbrIncrementTableCount ( + UINT32 Signature + ); + +/** + Validate that all ACPI tables required by the given SBBR specification + version are installed on the platform. + + @param [in] Version SBBR spec version to validate against. + + @retval EFI_SUCCESS All required tables are present. + @retval EFI_INVALID_PARAMETER Invalid SBBR version. + @retval EFI_NOT_FOUND One or more mandatory tables are missing. + @retval EFI_UNSUPPORTED Mandatory ACPI table does not have its + instance count tracked. +**/ +EFI_STATUS +EFIAPI +ArmSbbrReqsValidate ( + ARM_SBBR_VERSION Version + ); + +#endif // SBBR_VALIDATOR_H_ diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Aest/AestParser.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Aest/AestParser.c new file mode 100644 index 00000000..110412a2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Aest/AestParser.c @@ -0,0 +1,755 @@ +/** @file + AEST table parser + + Copyright (c) 2020, Arm Limited. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - ACPI for the Armv8 RAS Extensions 1.1 Platform Design Document, + dated 28 September 2020. + (https://developer.arm.com/documentation/den0085/0101/) +**/ + +#include +#include +#include +#include "AcpiParser.h" +#include "AcpiView.h" +#include "AcpiViewConfig.h" + +// Local variables +STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo; +STATIC UINT8* AestNodeType; +STATIC UINT16* AestNodeLength; +STATIC UINT32* NodeDataOffset; +STATIC UINT32* NodeInterfaceOffset; +STATIC UINT32* NodeInterruptArrayOffset; +STATIC UINT32* NodeInterruptCount; +STATIC UINT32* ProcessorId; +STATIC UINT8* ProcessorFlags; +STATIC UINT8* ProcessorResourceType; + +/** + Validate Processor Flags. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateProcessorFlags ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + // If the global or shared node flag is set then the ACPI Processor ID + // field must be set to 0 and ignored. + if (((*Ptr & 0x3) != 0) && (*ProcessorId != 0)) { + IncrementErrorCount (); + Print (L"\nERROR: 'ACPI Processor ID' field must be set to 0 for global" + L" or shared nodes."); + } +} + +/** + Validate GIC Interface Type. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateGicInterfaceType ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + UINT32 GicInterfaceType; + + GicInterfaceType = *(UINT32*)Ptr; + if (GicInterfaceType > 3) { + IncrementErrorCount (); + Print (L"\nError: Invalid GIC Interface type %d", GicInterfaceType); + } +} + +/** + Validate Interface Type. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateInterfaceType ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + if (*Ptr > 1) { + IncrementErrorCount (); + Print (L"\nError: Interface type should be 0 or 1"); + } +} + +/** + Validate Interrupt Type. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateInterruptType ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + if (*Ptr > 1) { + IncrementErrorCount (); + Print (L"\nError: Interrupt type should be 0 or 1"); + } +} + +/** + Validate interrupt flags. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateInterruptFlags ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + if ((*Ptr & 0xfe) != 0) { + IncrementErrorCount (); + Print (L"\nError: Reserved Flag bits not set to 0"); + } +} + +/** + Dumps 16 bytes of data. + + @param [in] Format Optional format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +VOID +EFIAPI +DumpVendorSpecificData ( + IN CONST CHAR16* Format OPTIONAL, + IN UINT8* Ptr + ) +{ + Print ( + L"%02X %02X %02X %02X %02X %02X %02X %02X\n", + Ptr[0], + Ptr[1], + Ptr[2], + Ptr[3], + Ptr[4], + Ptr[5], + Ptr[6], + Ptr[7] + ); + + Print ( + L"%*a %02X %02X %02X %02X %02X %02X %02X %02X", + OUTPUT_FIELD_COLUMN_WIDTH, + "", + Ptr[8], + Ptr[9], + Ptr[10], + Ptr[11], + Ptr[12], + Ptr[13], + Ptr[14], + Ptr[15] + ); +} + +/** + An ACPI_PARSER array describing the ACPI AEST Table. +**/ +STATIC CONST ACPI_PARSER AestParser[] = { + PARSE_ACPI_HEADER (&AcpiHdrInfo) +}; + +/** + An ACPI_PARSER array describing the AEST Node Header. +**/ +STATIC CONST ACPI_PARSER AestNodeHeaderParser[] = { + {L"Type", 1, 0, L"%d", NULL, (VOID**)&AestNodeType, NULL, NULL}, + {L"Length", 2, 1, L"%d", NULL, (VOID**)&AestNodeLength, NULL, NULL}, + {L"Reserved", 1, 3, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Node Data Offset", 4, 4, L"%d", NULL, (VOID**)&NodeDataOffset, NULL, NULL}, + {L"Node Interface Offset", 4, 8, L"%d", NULL, + (VOID**)&NodeInterfaceOffset, NULL, NULL}, + {L"Node Interrupt Array Offset", 4, 12, L"%d", NULL, + (VOID**)&NodeInterruptArrayOffset, NULL, NULL}, + {L"Node Interrupt Count", 4, 16, L"%d", NULL, + (VOID**)&NodeInterruptCount, NULL, NULL}, + {L"Timestamp Rate", 8, 20, L"%ld", NULL, NULL, NULL, NULL}, + {L"Reserved1", 8, 28, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Error Injection Countdown Rate", 8, 36, L"%ld", NULL, NULL, NULL, NULL} + // Node specific data... + // Node interface... + // Node interrupt array... +}; + +/** + An ACPI_PARSER array describing the Processor error node specific data. +**/ +STATIC CONST ACPI_PARSER AestProcessorStructure[] = { + {L"ACPI Processor ID", 4, 0, L"0x%x", NULL, (VOID**)&ProcessorId, NULL, NULL}, + {L"Resource Type", 1, 4, L"%d", NULL, (VOID**)&ProcessorResourceType, NULL, + NULL}, + {L"Reserved", 1, 5, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Flags", 1, 6, L"0x%x", NULL, (VOID**)&ProcessorFlags, + ValidateProcessorFlags, NULL}, + {L"Revision", 1, 7, L"%d", NULL, NULL, NULL, NULL}, + {L"Processor Affinity Level Indicator", 8, 8, L"0x%lx", NULL, NULL, NULL, + NULL}, + // Resource specific data... +}; + +/** + An ACPI_PARSER array describing the processor cache resource substructure. +**/ +STATIC CONST ACPI_PARSER AestProcessorCacheResourceSubstructure[] = { + {L"Cache reference ID", 4, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 4, 4, L"%d", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the processor TLB resource substructure. +**/ +STATIC CONST ACPI_PARSER AestProcessorTlbResourceSubstructure[] = { + {L"TLB reference ID", 4, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 4, 4, L"%d", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the processor generic resource substructure. +**/ +STATIC CONST ACPI_PARSER AestProcessorGenericResourceSubstructure[] = { + {L"Vendor-defined data", 4, 0, L"%x", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the memory controller structure. +**/ +STATIC CONST ACPI_PARSER AestMemoryControllerStructure[] = { + {L"Proximity Domain", 4, 0, L"0x%x", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the SMMU structure. +**/ +STATIC CONST ACPI_PARSER AestSmmuStructure[] = { + {L"IORT Node reference ID", 4, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"SubComponent reference ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the vendor-defined structure. +**/ +STATIC CONST ACPI_PARSER AestVendorDefinedStructure[] = { + {L"Hardware ID", 4, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Unique ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Vendor-specific data", 16, 8, NULL, DumpVendorSpecificData, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the GIC structure. +**/ +STATIC CONST ACPI_PARSER AestGicStructure[] = { + {L"GIC Interface Type", 4, 0, L"0x%x", NULL, NULL, ValidateGicInterfaceType, + NULL}, + {L"GIC Interface reference ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the node interface. +**/ +STATIC CONST ACPI_PARSER AestNodeInterface[] = { + {L"Interface Type", 1, 0, L"%d", NULL, NULL, ValidateInterfaceType, NULL}, + {L"Reserved", 3, 1, L"%x %x %x", Dump3Chars, NULL, NULL, NULL}, + {L"Flags", 4, 4, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Start Error Record Index", 4, 16, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Number of Error Records", 4, 20, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Error Records Implemented", 8, 24, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Error Records Support", 8, 32, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Addressing mode", 8, 40, L"0x%lx", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the node interrupts. +**/ +STATIC CONST ACPI_PARSER AestNodeInterrupt[] = { + {L"Interrupt Type", 1, 0, L"%d", NULL, NULL, ValidateInterruptType, NULL}, + {L"Reserved", 2, 1, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Interrupt Flags", 1, 3, L"0x%x", NULL, NULL, ValidateInterruptFlags, NULL}, + {L"Interrupt GSIV", 4, 4, L"0x%x", NULL, NULL, NULL, NULL}, + {L"ID", 1, 8, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved1", 3, 9, L"%x %x %x", Dump3Chars, NULL, NULL, NULL} +}; + +/** + Parses the Processor Error Node structure along with its resource + specific data. + + @param [in] Ptr Pointer to the start of the Processor node. + @param [in] Length Maximum length of the Processor node. +**/ +STATIC +VOID +DumpProcessorNode ( + IN UINT8* Ptr, + IN UINT32 Length + ) +{ + UINT32 Offset; + + Offset = ParseAcpi ( + TRUE, + 2, + "Processor", + Ptr, + Length, + PARSER_PARAMS (AestProcessorStructure) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if ((ProcessorId == NULL) || + (ProcessorResourceType == NULL) || + (ProcessorFlags == NULL)) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient Processor Error Node length. Length = %d.\n", + Length + ); + return; + } + + switch (*ProcessorResourceType) { + case EFI_ACPI_AEST_PROCESSOR_RESOURCE_TYPE_CACHE: + ParseAcpi ( + TRUE, + 2, + "Cache Resource", + Ptr + Offset, + Length - Offset, + PARSER_PARAMS (AestProcessorCacheResourceSubstructure) + ); + break; + case EFI_ACPI_AEST_PROCESSOR_RESOURCE_TYPE_TLB: + ParseAcpi ( + TRUE, + 2, + "TLB Resource", + Ptr + Offset, + Length - Offset, + PARSER_PARAMS (AestProcessorTlbResourceSubstructure) + ); + break; + case EFI_ACPI_AEST_PROCESSOR_RESOURCE_TYPE_GENERIC: + ParseAcpi ( + TRUE, + 2, + "Generic Resource", + Ptr + Offset, + Length - Offset, + PARSER_PARAMS (AestProcessorGenericResourceSubstructure) + ); + break; + default: + IncrementErrorCount (); + Print (L"ERROR: Invalid Processor Resource Type."); + return; + } // switch +} + +/** + Parses the Memory Controller node. + + @param [in] Ptr Pointer to the start of the Memory Controller node. + @param [in] Length Maximum length of the Memory Controller node. +**/ +STATIC +VOID +DumpMemoryControllerNode ( + IN UINT8* Ptr, + IN UINT32 Length + ) +{ + ParseAcpi ( + TRUE, + 2, + "Memory Controller", + Ptr, + Length, + PARSER_PARAMS (AestMemoryControllerStructure) + ); +} + +/** + Parses the SMMU node. + + @param [in] Ptr Pointer to the start of the SMMU node. + @param [in] Length Maximum length of the SMMU node. +**/ +STATIC +VOID +DumpSmmuNode ( + IN UINT8* Ptr, + IN UINT32 Length + ) +{ + ParseAcpi ( + TRUE, + 2, + "SMMU", + Ptr, + Length, + PARSER_PARAMS (AestSmmuStructure) + ); +} + +/** + Parses the Vendor-defined structure. + + @param [in] Ptr Pointer to the start of the Vendor-defined node. + @param [in] Length Maximum length of the Vendor-defined node. +**/ +STATIC +VOID +DumpVendorDefinedNode ( + IN UINT8* Ptr, + IN UINT32 Length + ) +{ + ParseAcpi ( + TRUE, + 2, + "Vendor-defined", + Ptr, + Length, + PARSER_PARAMS (AestVendorDefinedStructure) + ); +} + +/** + Parses the GIC node. + + @param [in] Ptr Pointer to the start of the GIC node. + @param [in] Length Maximum length of the GIC node. +**/ +STATIC +VOID +DumpGicNode ( + IN UINT8* Ptr, + IN UINT32 Length + ) +{ + ParseAcpi ( + TRUE, + 2, + "GIC", + Ptr, + Length, + PARSER_PARAMS (AestGicStructure) + ); +} + +/** + Parses the Node Interface structure. + + @param [in] Ptr Pointer to the start of the Node Interface Structure. + @param [in] Length Maximum length of the Node Interface Structure. +**/ +STATIC +VOID +DumpNodeInterface ( + IN UINT8* Ptr, + IN UINT32 Length + ) +{ + ParseAcpi ( + TRUE, + 2, + "Node Interface", + Ptr, + Length, + PARSER_PARAMS (AestNodeInterface) + ); +} + +/** + Parses the Node Interrupts Structure. + + @param [in] Ptr Pointer to the start of the Node Interrupt array. + @param [in] Length Maximum length of the Node Interrupt array. + @param [in] InterruptCount Number if interrupts in the Node Interrupts array. +**/ +STATIC +VOID +DumpNodeInterrupts ( + IN UINT8* Ptr, + IN UINT32 Length, + IN UINT32 InterruptCount + ) +{ + UINT32 Offset; + UINT32 Index; + CHAR8 Buffer[64]; + + if (Length < (InterruptCount * sizeof (EFI_ACPI_AEST_INTERRUPT_STRUCT))) { + IncrementErrorCount (); + Print ( + L"ERROR: Node not long enough for Interrupt Array.\n"\ + L" Length left = %d, Required = %d, Interrupt Count = %d\n", + Length, + (InterruptCount * sizeof (EFI_ACPI_AEST_INTERRUPT_STRUCT)), + InterruptCount + ); + return; + } + + Offset = 0; + for (Index = 0; Index < InterruptCount; Index++) { + AsciiSPrint ( + Buffer, + sizeof (Buffer), + "Node Interrupt [%d]", + Index + ); + + Offset += ParseAcpi ( + TRUE, + 4, + Buffer, + Ptr + Offset, + Length - Offset, + PARSER_PARAMS (AestNodeInterrupt) + ); + } //for +} + +/** + Parses a single AEST Node Structure. + + @param [in] Ptr Pointer to the start of the Node. + @param [in] Length Maximum length of the Node. + @param [in] NodeType AEST node type. + @param [in] DataOffset Offset to the node data. + @param [in] InterfaceOffset Offset to the node interface data. + @param [in] InterruptArrayOffset Offset to the node interrupt array. + @param [in] InterruptCount Number of interrupts. +**/ +STATIC +VOID +DumpAestNodeStructure ( + IN UINT8* Ptr, + IN UINT32 Length, + IN UINT8 NodeType, + IN UINT32 DataOffset, + IN UINT32 InterfaceOffset, + IN UINT32 InterruptArrayOffset, + IN UINT32 InterruptCount + ) +{ + UINT32 Offset; + UINT32 RemainingLength; + UINT8* NodeDataPtr; + + Offset = ParseAcpi ( + TRUE, + 2, + "Node Structure", + Ptr, + Length, + PARSER_PARAMS (AestNodeHeaderParser) + ); + + if ((Offset > DataOffset) || (DataOffset > Length)) { + IncrementErrorCount (); + Print ( + L"ERROR: Invalid Node Data Offset: %d.\n"\ + L" It should be between %d and %d.\n", + DataOffset, + Offset, + Length + ); + } + + if ((Offset > InterfaceOffset) || (InterfaceOffset > Length)) { + IncrementErrorCount (); + Print ( + L"ERROR: Invalid Node Interface Offset: %d.\n"\ + L" It should be between %d and %d.\n", + InterfaceOffset, + Offset, + Length + ); + } + + if ((Offset > InterruptArrayOffset) || (InterruptArrayOffset > Length)) { + IncrementErrorCount (); + Print ( + L"ERROR: Invalid Node Interrupt Array Offset: %d.\n"\ + L" It should be between %d and %d.\n", + InterruptArrayOffset, + Offset, + Length + ); + } + + // Parse Node Data Field. + NodeDataPtr = Ptr + DataOffset; + RemainingLength = Length - DataOffset; + switch (NodeType) { + case EFI_ACPI_AEST_NODE_TYPE_PROCESSOR: + DumpProcessorNode (NodeDataPtr, RemainingLength); + break; + case EFI_ACPI_AEST_NODE_TYPE_MEMORY: + DumpMemoryControllerNode (NodeDataPtr, RemainingLength); + break; + case EFI_ACPI_AEST_NODE_TYPE_SMMU: + DumpSmmuNode (NodeDataPtr, RemainingLength); + break; + case EFI_ACPI_AEST_NODE_TYPE_VENDOR_DEFINED: + DumpVendorDefinedNode (NodeDataPtr, RemainingLength); + break; + case EFI_ACPI_AEST_NODE_TYPE_GIC: + DumpGicNode (NodeDataPtr, RemainingLength); + break; + default: + IncrementErrorCount (); + Print (L"ERROR: Invalid Error Node Type.\n"); + return; + } // switch + + // Parse the Interface Field. + DumpNodeInterface ( + Ptr + InterfaceOffset, + Length - InterfaceOffset + ); + + // Parse the Node Interrupt Array. + DumpNodeInterrupts ( + Ptr + InterruptArrayOffset, + Length - InterruptArrayOffset, + InterruptCount + ); + + return; +} + +/** + This function parses the ACPI AEST table. + When trace is enabled this function parses the AEST table and + traces the ACPI table fields. + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiAest ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ) +{ + UINT32 Offset; + UINT8* NodePtr; + + if (!Trace) { + return; + } + + Offset = ParseAcpi ( + TRUE, + 0, + "AEST", + Ptr, + AcpiTableLength, + PARSER_PARAMS (AestParser) + ); + + while (Offset < AcpiTableLength) { + NodePtr = Ptr + Offset; + + ParseAcpi ( + FALSE, + 0, + NULL, + NodePtr, + AcpiTableLength - Offset, + PARSER_PARAMS (AestNodeHeaderParser) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if ((AestNodeType == NULL) || + (AestNodeLength == NULL) || + (NodeDataOffset == NULL) || + (NodeInterfaceOffset == NULL) || + (NodeInterruptArrayOffset == NULL) || + (NodeInterruptCount == NULL)) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient length left for Node Structure.\n"\ + L" Length left = %d.\n", + AcpiTableLength - Offset + ); + return; + } + + // Validate AEST Node length + if ((*AestNodeLength == 0) || + ((Offset + (*AestNodeLength)) > AcpiTableLength)) { + IncrementErrorCount (); + Print ( + L"ERROR: Invalid AEST Node length. " \ + L"Length = %d. Offset = %d. AcpiTableLength = %d.\n", + *AestNodeLength, + Offset, + AcpiTableLength + ); + return; + } + + DumpAestNodeStructure ( + NodePtr, + *AestNodeLength, + *AestNodeType, + *NodeDataOffset, + *NodeInterfaceOffset, + *NodeInterruptArrayOffset, + *NodeInterruptCount + ); + + Offset += *AestNodeLength; + } // while +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Bgrt/BgrtParser.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Bgrt/BgrtParser.c new file mode 100644 index 00000000..0df8c5ae --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Bgrt/BgrtParser.c @@ -0,0 +1,65 @@ +/** @file + BGRT table parser + + Copyright (c) 2017 - 2018, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - ACPI 6.2 Specification - Errata A, September 2017 +**/ + +#include +#include +#include "AcpiParser.h" +#include "AcpiTableParser.h" + +// Local variables +STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo; + +/** + An ACPI_PARSER array describing the ACPI BDRT Table. +**/ +STATIC CONST ACPI_PARSER BgrtParser[] = { + PARSE_ACPI_HEADER (&AcpiHdrInfo), + {L"Version", 2, 36, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Status", 1, 38, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Image Type", 1, 39, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Image Address", 8, 40, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Image Offset X", 4, 48, L"%d", NULL, NULL, NULL, NULL}, + {L"Image Offset Y", 4, 52, L"%d", NULL, NULL, NULL, NULL} +}; + +/** + This function parses the ACPI BGRT table. + When trace is enabled this function parses the BGRT table and + traces the ACPI table fields. + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiBgrt ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ) +{ + if (!Trace) { + return; + } + + ParseAcpi ( + Trace, + 0, + "BGRT", + Ptr, + AcpiTableLength, + PARSER_PARAMS (BgrtParser) + ); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Dbg2/Dbg2Parser.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Dbg2/Dbg2Parser.c new file mode 100644 index 00000000..22e36695 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Dbg2/Dbg2Parser.c @@ -0,0 +1,302 @@ +/** @file + DBG2 table parser + + Copyright (c) 2016 - 2020, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - Microsoft Debug Port Table 2 (DBG2) Specification - December 10, 2015. +**/ + +#include +#include +#include "AcpiParser.h" +#include "AcpiTableParser.h" + +// Local variables pointing to the table fields +STATIC CONST UINT32* OffsetDbgDeviceInfo; +STATIC CONST UINT32* NumberDbgDeviceInfo; +STATIC CONST UINT16* DbgDevInfoLen; +STATIC CONST UINT8* GasCount; +STATIC CONST UINT16* NameSpaceStringLength; +STATIC CONST UINT16* NameSpaceStringOffset; +STATIC CONST UINT16* OEMDataLength; +STATIC CONST UINT16* OEMDataOffset; +STATIC CONST UINT16* BaseAddrRegOffset; +STATIC CONST UINT16* AddrSizeOffset; +STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo; + +/** + This function validates the NameSpace string length. + + @param [in] Ptr Pointer to the start of the buffer. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateNameSpaceStrLen ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + UINT16 NameSpaceStrLen; + + NameSpaceStrLen = *(UINT16*)Ptr; + + if (NameSpaceStrLen < 2) { + IncrementErrorCount (); + Print ( + L"\nERROR: NamespaceString Length = %d. If no Namespace device exists, " \ + L"NamespaceString[] must contain a period '.'", + NameSpaceStrLen + ); + } +} + +/// An ACPI_PARSER array describing the ACPI DBG2 table. +STATIC CONST ACPI_PARSER Dbg2Parser[] = { + PARSE_ACPI_HEADER (&AcpiHdrInfo), + {L"OffsetDbgDeviceInfo", 4, 36, L"0x%x", NULL, + (VOID**)&OffsetDbgDeviceInfo, NULL, NULL}, + {L"NumberDbgDeviceInfo", 4, 40, L"%d", NULL, + (VOID**)&NumberDbgDeviceInfo, NULL, NULL} +}; + +/// An ACPI_PARSER array describing the debug device information structure +/// header. +STATIC CONST ACPI_PARSER DbgDevInfoHeaderParser[] = { + {L"Revision", 1, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Length", 2, 1, L"%d", NULL, (VOID**)&DbgDevInfoLen, NULL, NULL} +}; + +/// An ACPI_PARSER array describing the debug device information. +STATIC CONST ACPI_PARSER DbgDevInfoParser[] = { + {L"Revision", 1, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Length", 2, 1, L"%d", NULL, NULL, NULL, NULL}, + + {L"Generic Address Registers Count", 1, 3, L"0x%x", NULL, + (VOID**)&GasCount, NULL, NULL}, + {L"NameSpace String Length", 2, 4, L"%d", NULL, + (VOID**)&NameSpaceStringLength, ValidateNameSpaceStrLen, NULL}, + {L"NameSpace String Offset", 2, 6, L"0x%x", NULL, + (VOID**)&NameSpaceStringOffset, NULL, NULL}, + {L"OEM Data Length", 2, 8, L"%d", NULL, (VOID**)&OEMDataLength, + NULL, NULL}, + {L"OEM Data Offset", 2, 10, L"0x%x", NULL, (VOID**)&OEMDataOffset, + NULL, NULL}, + + {L"Port Type", 2, 12, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Port SubType", 2, 14, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 2, 16, L"%x", NULL, NULL, NULL, NULL}, + + {L"Base Address Register Offset", 2, 18, L"0x%x", NULL, + (VOID**)&BaseAddrRegOffset, NULL, NULL}, + {L"Address Size Offset", 2, 20, L"0x%x", NULL, + (VOID**)&AddrSizeOffset, NULL, NULL} +}; + +/** + This function parses the debug device information structure. + + @param [in] Ptr Pointer to the start of the buffer. + @param [in] Length Length of the debug device information structure. +**/ +STATIC +VOID +EFIAPI +DumpDbgDeviceInfo ( + IN UINT8* Ptr, + IN UINT16 Length + ) +{ + UINT16 Index; + UINT16 Offset; + + ParseAcpi ( + TRUE, + 2, + "Debug Device Info", + Ptr, + Length, + PARSER_PARAMS (DbgDevInfoParser) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if ((GasCount == NULL) || + (NameSpaceStringLength == NULL) || + (NameSpaceStringOffset == NULL) || + (OEMDataLength == NULL) || + (OEMDataOffset == NULL) || + (BaseAddrRegOffset == NULL) || + (AddrSizeOffset == NULL)) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient Debug Device Information Structure length. " \ + L"Length = %d.\n", + Length + ); + return; + } + + // GAS + Index = 0; + Offset = *BaseAddrRegOffset; + while ((Index++ < *GasCount) && + (Offset < Length)) { + PrintFieldName (4, L"BaseAddressRegister"); + Offset += (UINT16)DumpGasStruct ( + Ptr + Offset, + 4, + Length - Offset + ); + } + + // Make sure the array of address sizes corresponding to each GAS fit in the + // Debug Device Information structure + if ((*AddrSizeOffset + (*GasCount * sizeof (UINT32))) > Length) { + IncrementErrorCount (); + Print ( + L"ERROR: Invalid GAS count. GasCount = %d. RemainingBufferLength = %d. " \ + L"Parsing of the Debug Device Information structure aborted.\n", + *GasCount, + Length - *AddrSizeOffset + ); + return; + } + + // Address Size + Index = 0; + Offset = *AddrSizeOffset; + while ((Index++ < *GasCount) && + (Offset < Length)) { + PrintFieldName (4, L"Address Size"); + Print (L"0x%x\n", *((UINT32*)(Ptr + Offset))); + Offset += sizeof (UINT32); + } + + // NameSpace String + Index = 0; + Offset = *NameSpaceStringOffset; + PrintFieldName (4, L"NameSpace String"); + while ((Index++ < *NameSpaceStringLength) && + (Offset < Length)) { + Print (L"%c", *(Ptr + Offset)); + Offset++; + } + Print (L"\n"); + + // OEM Data + if (*OEMDataOffset != 0) { + Index = 0; + Offset = *OEMDataOffset; + PrintFieldName (4, L"OEM Data"); + while ((Index++ < *OEMDataLength) && + (Offset < Length)) { + Print (L"%x ", *(Ptr + Offset)); + if ((Index & 7) == 0) { + Print (L"\n%-*s ", OUTPUT_FIELD_COLUMN_WIDTH, L""); + } + Offset++; + } + Print (L"\n"); + } +} + +/** + This function parses the ACPI DBG2 table. + When trace is enabled this function parses the DBG2 table and + traces the ACPI table fields. + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiDbg2 ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ) +{ + UINT32 Offset; + UINT32 Index; + + if (!Trace) { + return; + } + + Offset = ParseAcpi ( + TRUE, + 0, + "DBG2", + Ptr, + AcpiTableLength, + PARSER_PARAMS (Dbg2Parser) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if ((OffsetDbgDeviceInfo == NULL) || + (NumberDbgDeviceInfo == NULL)) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient table length. AcpiTableLength = %d\n", + AcpiTableLength + ); + return; + } + + Offset = *OffsetDbgDeviceInfo; + Index = 0; + + while (Index++ < *NumberDbgDeviceInfo) { + + // Parse the Debug Device Information Structure header to obtain Length + ParseAcpi ( + FALSE, + 0, + NULL, + Ptr + Offset, + AcpiTableLength - Offset, + PARSER_PARAMS (DbgDevInfoHeaderParser) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if (DbgDevInfoLen == NULL) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient remaining table buffer length to read the " \ + L"Debug Device Information structure's 'Length' field. " \ + L"RemainingTableBufferLength = %d.\n", + AcpiTableLength - Offset + ); + return; + } + + // Validate Debug Device Information Structure length + if ((*DbgDevInfoLen == 0) || + ((Offset + (*DbgDevInfoLen)) > AcpiTableLength)) { + IncrementErrorCount (); + Print ( + L"ERROR: Invalid Debug Device Information Structure length. " \ + L"Length = %d. Offset = %d. AcpiTableLength = %d.\n", + *DbgDevInfoLen, + Offset, + AcpiTableLength + ); + return; + } + + DumpDbgDeviceInfo (Ptr + Offset, (*DbgDevInfoLen)); + Offset += (*DbgDevInfoLen); + } +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Dsdt/DsdtParser.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Dsdt/DsdtParser.c new file mode 100644 index 00000000..cd6cdd41 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Dsdt/DsdtParser.c @@ -0,0 +1,42 @@ +/** @file + DSDT table parser + + Copyright (c) 2016 - 2018, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - ACPI 6.2 Specification - Errata A, September 2017 +**/ + +#include +#include +#include "AcpiParser.h" +#include "AcpiTableParser.h" + +/** + This function parses the ACPI DSDT table. + When trace is enabled this function parses the DSDT table and + traces the ACPI table fields. + For the DSDT table only the ACPI header fields are parsed and + traced. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiDsdt ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ) +{ + if (!Trace) { + return; + } + + DumpAcpiHeader (Ptr); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Facs/FacsParser.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Facs/FacsParser.c new file mode 100644 index 00000000..1531ee56 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Facs/FacsParser.c @@ -0,0 +1,71 @@ +/** @file + FACS table parser + + Copyright (c) 2019, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - ACPI 6.3 Specification - January 2019 +**/ + +#include +#include +#include "AcpiParser.h" +#include "AcpiTableParser.h" + +/** + An ACPI_PARSER array describing the ACPI FACS Table. +**/ +STATIC CONST ACPI_PARSER FacsParser[] = { + {L"Signature", 4, 0, L"%c%c%c%c", Dump4Chars, NULL, NULL, NULL}, + {L"Length", 4, 4, L"%d", NULL, NULL, NULL, NULL}, + {L"Hardware Signature", 4, 8, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Firmware Waking Vector", 4, 12, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Global Lock", 4, 16, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Flags", 4, 20, L"0x%x", NULL, NULL, NULL, NULL}, + {L"X Firmware Walking Vector", 8, 24, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Version", 1, 32, L"%d", NULL, NULL, NULL, NULL}, + {L"Reserved", 3, 33, L"%x %x %x", Dump3Chars, NULL, NULL, NULL}, + {L"OSPM Flags", 4, 36, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 8, 40, L"%x %x %x %x %x %x %x %x", Dump8Chars, NULL, NULL, + NULL}, + {L"Reserved", 8, 48, L"%x %x %x %x %x %x %x %x", Dump8Chars, NULL, NULL, + NULL}, + {L"Reserved", 8, 56, L"%x %x %x %x %x %x %x %x", Dump8Chars, NULL, NULL, + NULL} +}; + +/** + This function parses the ACPI FACS table. + When trace is enabled this function parses the FACS table and + traces the ACPI table fields. + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiFacs ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ) +{ + if (!Trace) { + return; + } + + ParseAcpi ( + Trace, + 0, + "FACS", + Ptr, + AcpiTableLength, + PARSER_PARAMS (FacsParser) + ); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Fadt/FadtParser.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Fadt/FadtParser.c new file mode 100644 index 00000000..6fe6f8e3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Fadt/FadtParser.c @@ -0,0 +1,319 @@ +/** @file + FADT table parser + + Copyright (c) 2016 - 2020, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - ACPI 6.3 Specification - January 2019 +**/ + +#include +#include +#include "AcpiParser.h" +#include "AcpiTableParser.h" +#include "AcpiView.h" + +// Local variables +STATIC CONST UINT32* DsdtAddress; +STATIC CONST UINT64* X_DsdtAddress; +STATIC CONST UINT32* Flags; +STATIC CONST UINT32* FirmwareCtrl; +STATIC CONST UINT64* X_FirmwareCtrl; +STATIC CONST UINT8* FadtMinorRevision; +STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo; + +/** + A macro defining the Hardware reduced ACPI flag +**/ +#define HW_REDUCED_ACPI BIT20 + +/** + Offset to the FACS signature from the start of the FACS. +**/ +#define FACS_SIGNATURE_OFFSET 0 + +/** + Offset to the FACS revision from the start of the FACS. +**/ +#define FACS_VERSION_OFFSET 32 + +/** + Offset to the FACS length from the start of the FACS. +**/ +#define FACS_LENGTH_OFFSET 4 + +/** + Get the ACPI XSDT header info. +**/ +CONST ACPI_DESCRIPTION_HEADER_INFO * +EFIAPI +GetAcpiXsdtHeaderInfo ( + VOID + ); + +/** + This function validates the Firmware Control Field. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateFirmwareCtrl ( + IN UINT8* Ptr, + IN VOID* Context +) +{ +#if defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64) + if (*(UINT32*)Ptr != 0) { + IncrementErrorCount (); + Print ( + L"\nERROR: Firmware Control must be zero for ARM platforms." + ); + } +#endif +} + +/** + This function validates the X_Firmware Control Field. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateXFirmwareCtrl ( + IN UINT8* Ptr, + IN VOID* Context +) +{ +#if defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64) + if (*(UINT64*)Ptr != 0) { + IncrementErrorCount (); + Print ( + L"\nERROR: X Firmware Control must be zero for ARM platforms." + ); + } +#endif +} + +/** + This function validates the flags. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateFlags ( + IN UINT8* Ptr, + IN VOID* Context +) +{ +#if defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64) + if (((*(UINT32*)Ptr) & HW_REDUCED_ACPI) == 0) { + IncrementErrorCount (); + Print ( + L"\nERROR: HW_REDUCED_ACPI flag must be set for ARM platforms." + ); + } +#endif +} + +/** + An ACPI_PARSER array describing the ACPI FADT Table. +**/ +STATIC CONST ACPI_PARSER FadtParser[] = { + PARSE_ACPI_HEADER (&AcpiHdrInfo), + {L"FIRMWARE_CTRL", 4, 36, L"0x%x", NULL, (VOID**)&FirmwareCtrl, + ValidateFirmwareCtrl, NULL}, + {L"DSDT", 4, 40, L"0x%x", NULL, (VOID**)&DsdtAddress, NULL, NULL}, + {L"Reserved", 1, 44, L"%x", NULL, NULL, NULL, NULL}, + {L"Preferred_PM_Profile", 1, 45, L"0x%x", NULL, NULL, NULL, NULL}, + {L"SCI_INT", 2, 46, L"0x%x", NULL, NULL, NULL, NULL}, + {L"SMI_CMD", 4, 48, L"0x%x", NULL, NULL, NULL, NULL}, + {L"ACPI_ENABLE", 1, 52, L"0x%x", NULL, NULL, NULL, NULL}, + {L"ACPI_DISABLE", 1, 53, L"0x%x", NULL, NULL, NULL, NULL}, + {L"S4BIOS_REQ", 1, 54, L"0x%x", NULL, NULL, NULL, NULL}, + {L"PSTATE_CNT", 1, 55, L"0x%x", NULL, NULL, NULL, NULL}, + {L"PM1a_EVT_BLK", 4, 56, L"0x%x", NULL, NULL, NULL, NULL}, + {L"PM1b_EVT_BLK", 4, 60, L"0x%x", NULL, NULL, NULL, NULL}, + {L"PM1a_CNT_BLK", 4, 64, L"0x%x", NULL, NULL, NULL, NULL}, + {L"PM1b_CNT_BLK", 4, 68, L"0x%x", NULL, NULL, NULL, NULL}, + {L"PM2_CNT_BLK", 4, 72, L"0x%x", NULL, NULL, NULL, NULL}, + {L"PM_TMR_BLK", 4, 76, L"0x%x", NULL, NULL, NULL, NULL}, + {L"GPE0_BLK", 4, 80, L"0x%x", NULL, NULL, NULL, NULL}, + {L"GPE1_BLK", 4, 84, L"0x%x", NULL, NULL, NULL, NULL}, + {L"PM1_EVT_LEN", 1, 88, L"0x%x", NULL, NULL, NULL, NULL}, + {L"PM1_CNT_LEN", 1, 89, L"0x%x", NULL, NULL, NULL, NULL}, + {L"PM2_CNT_LEN", 1, 90, L"0x%x", NULL, NULL, NULL, NULL}, + {L"PM_TMR_LEN", 1, 91, L"0x%x", NULL, NULL, NULL, NULL}, + {L"GPE0_BLK_LEN", 1, 92, L"0x%x", NULL, NULL, NULL, NULL}, + {L"GPE1_BLK_LEN", 1, 93, L"0x%x", NULL, NULL, NULL, NULL}, + {L"GPE1_BASE", 1, 94, L"0x%x", NULL, NULL, NULL, NULL}, + {L"CST_CNT", 1, 95, L"0x%x", NULL, NULL, NULL, NULL}, + {L"P_LVL2_LAT", 2, 96, L"0x%x", NULL, NULL, NULL, NULL}, + {L"P_LVL3_LAT", 2, 98, L"0x%x", NULL, NULL, NULL, NULL}, + {L"FLUSH_SIZE", 2, 100, L"0x%x", NULL, NULL, NULL, NULL}, + {L"FLUSH_STRIDE", 2, 102, L"0x%x", NULL, NULL, NULL, NULL}, + {L"DUTY_OFFSET", 1, 104, L"0x%x", NULL, NULL, NULL, NULL}, + {L"DUTY_WIDTH", 1, 105, L"0x%x", NULL, NULL, NULL, NULL}, + {L"DAY_ALRM", 1, 106, L"0x%x", NULL, NULL, NULL, NULL}, + {L"MON_ALRM", 1, 107, L"0x%x", NULL, NULL, NULL, NULL}, + {L"CENTURY", 1, 108, L"0x%x", NULL, NULL, NULL, NULL}, + {L"IAPC_BOOT_ARCH", 2, 109, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 1, 111, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Flags", 4, 112, L"0x%x", NULL, (VOID**)&Flags, ValidateFlags, NULL}, + {L"RESET_REG", 12, 116, NULL, DumpGas, NULL, NULL, NULL}, + {L"RESET_VALUE", 1, 128, L"0x%x", NULL, NULL, NULL, NULL}, + {L"ARM_BOOT_ARCH", 2, 129, L"0x%x", NULL, NULL, NULL, NULL}, + {L"FADT Minor Version", 1, 131, L"0x%x", NULL, (VOID**)&FadtMinorRevision, + NULL, NULL}, + {L"X_FIRMWARE_CTRL", 8, 132, L"0x%lx", NULL, (VOID**)&X_FirmwareCtrl, + ValidateXFirmwareCtrl, NULL}, + {L"X_DSDT", 8, 140, L"0x%lx", NULL, (VOID**)&X_DsdtAddress, NULL, NULL}, + {L"X_PM1a_EVT_BLK", 12, 148, NULL, DumpGas, NULL, NULL, NULL}, + {L"X_PM1b_EVT_BLK", 12, 160, NULL, DumpGas, NULL, NULL, NULL}, + {L"X_PM1a_CNT_BLK", 12, 172, NULL, DumpGas, NULL, NULL, NULL}, + {L"X_PM1b_CNT_BLK", 12, 184, NULL, DumpGas, NULL, NULL, NULL}, + {L"X_PM2_CNT_BLK", 12, 196, NULL, DumpGas, NULL, NULL, NULL}, + {L"X_PM_TMR_BLK", 12, 208, NULL, DumpGas, NULL, NULL, NULL}, + {L"X_GPE0_BLK", 12, 220, NULL, DumpGas, NULL, NULL, NULL}, + {L"X_GPE1_BLK", 12, 232, NULL, DumpGas, NULL, NULL, NULL}, + {L"SLEEP_CONTROL_REG", 12, 244, NULL, DumpGas, NULL, NULL, NULL}, + {L"SLEEP_STATUS_REG", 12, 256, NULL, DumpGas, NULL, NULL, NULL}, + {L"Hypervisor VendorIdentity", 8, 268, L"%lx", NULL, NULL, NULL, NULL} +}; + +/** + This function parses the ACPI FADT table. + This function parses the FADT table and optionally traces the ACPI table fields. + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiFadt ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ) +{ + EFI_STATUS Status; + UINT8* DsdtPtr; + UINT8* FirmwareCtrlPtr; + UINT32 FacsSignature; + UINT32 FacsLength; + UINT8 FacsRevision; + PARSE_ACPI_TABLE_PROC FacsParserProc; + + ParseAcpi ( + Trace, + 0, + "FADT", + Ptr, + AcpiTableLength, + PARSER_PARAMS (FadtParser) + ); + + if (Trace) { + if (FadtMinorRevision != NULL) { + Print (L"\nSummary:\n"); + PrintFieldName (2, L"FADT Version"); + Print (L"%d.%d\n", *AcpiHdrInfo.Revision, *FadtMinorRevision); + } + + if (*GetAcpiXsdtHeaderInfo ()->OemTableId != *AcpiHdrInfo.OemTableId) { + IncrementErrorCount (); + Print (L"ERROR: OEM Table Id does not match with RSDT/XSDT.\n"); + } + } + + // If X_FIRMWARE_CTRL is not zero then use X_FIRMWARE_CTRL and ignore + // FIRMWARE_CTRL, else use FIRMWARE_CTRL. + if ((X_FirmwareCtrl != NULL) && (*X_FirmwareCtrl != 0)) { + FirmwareCtrlPtr = (UINT8*)(UINTN)(*X_FirmwareCtrl); + } else if ((FirmwareCtrl != NULL) && (*FirmwareCtrl != 0)) { + FirmwareCtrlPtr = (UINT8*)(UINTN)(*FirmwareCtrl); + } else { + FirmwareCtrlPtr = NULL; + // if HW_REDUCED_ACPI flag is not set, both FIRMWARE_CTRL and + // X_FIRMWARE_CTRL cannot be zero, and the FACS Table must be + // present. + if ((Trace) && + (Flags != NULL) && + ((*Flags & EFI_ACPI_6_3_HW_REDUCED_ACPI) != EFI_ACPI_6_3_HW_REDUCED_ACPI)) { + IncrementErrorCount (); + Print (L"ERROR: No FACS table found, " + L"both X_FIRMWARE_CTRL and FIRMWARE_CTRL are zero.\n"); + } + } + + if (FirmwareCtrlPtr != NULL) { + // The FACS table does not have a standard ACPI table header. Therefore, + // the signature, length and version needs to be initially parsed. + // The FACS signature is 4 bytes starting at offset 0. + FacsSignature = *(UINT32*)(FirmwareCtrlPtr + FACS_SIGNATURE_OFFSET); + + // The FACS length is 4 bytes starting at offset 4. + FacsLength = *(UINT32*)(FirmwareCtrlPtr + FACS_LENGTH_OFFSET); + + // The FACS version is 1 byte starting at offset 32. + FacsRevision = *(UINT8*)(FirmwareCtrlPtr + FACS_VERSION_OFFSET); + + Trace = ProcessTableReportOptions ( + FacsSignature, + FirmwareCtrlPtr, + FacsLength + ); + + Status = GetParser (FacsSignature, &FacsParserProc); + if (EFI_ERROR (Status)) { + Print ( + L"ERROR: No registered parser found for FACS.\n" + ); + return; + } + + FacsParserProc ( + Trace, + FirmwareCtrlPtr, + FacsLength, + FacsRevision + ); + } + + // If X_DSDT is valid then use X_DSDT and ignore DSDT, else use DSDT. + if ((X_DsdtAddress != NULL) && (*X_DsdtAddress != 0)) { + DsdtPtr = (UINT8*)(UINTN)(*X_DsdtAddress); + } else if ((DsdtAddress != NULL) && (*DsdtAddress != 0)) { + DsdtPtr = (UINT8*)(UINTN)(*DsdtAddress); + } else { + // Both DSDT and X_DSDT cannot be invalid. +#if defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64) + if (Trace) { + // The DSDT Table is mandatory for ARM systems + // as the CPU information MUST be presented in + // the DSDT. + IncrementErrorCount (); + Print (L"ERROR: Both X_DSDT and DSDT are invalid.\n"); + } +#endif + return; + } + + ProcessAcpiTable (DsdtPtr); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Gtdt/GtdtParser.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Gtdt/GtdtParser.c new file mode 100644 index 00000000..f490f07c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Gtdt/GtdtParser.c @@ -0,0 +1,364 @@ +/** @file + GTDT table parser + + Copyright (c) 2016 - 2020, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - ACPI 6.3 Specification - January 2019 + **/ + +#include +#include +#include "AcpiParser.h" +#include "AcpiTableParser.h" +#include "AcpiViewConfig.h" + +// "The number of GT Block Timers must be less than or equal to 8" +#define GT_BLOCK_TIMER_COUNT_MAX 8 + +// Local variables +STATIC CONST UINT32* GtdtPlatformTimerCount; +STATIC CONST UINT32* GtdtPlatformTimerOffset; +STATIC CONST UINT8* PlatformTimerType; +STATIC CONST UINT16* PlatformTimerLength; +STATIC CONST UINT32* GtBlockTimerCount; +STATIC CONST UINT32* GtBlockTimerOffset; +STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo; + +/** + This function validates the GT Block timer count. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateGtBlockTimerCount ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + UINT32 BlockTimerCount; + + BlockTimerCount = *(UINT32*)Ptr; + + if (BlockTimerCount > GT_BLOCK_TIMER_COUNT_MAX) { + IncrementErrorCount (); + Print ( + L"\nERROR: Timer Count = %d. Max Timer Count is %d.", + BlockTimerCount, + GT_BLOCK_TIMER_COUNT_MAX + ); + } +} + +/** + This function validates the GT Frame Number. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateGtFrameNumber ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + UINT8 FrameNumber; + + FrameNumber = *(UINT8*)Ptr; + + if (FrameNumber >= GT_BLOCK_TIMER_COUNT_MAX) { + IncrementErrorCount (); + Print ( + L"\nERROR: GT Frame Number = %d. GT Frame Number must be in range 0-%d.", + FrameNumber, + GT_BLOCK_TIMER_COUNT_MAX - 1 + ); + } +} + +/** + An ACPI_PARSER array describing the ACPI GTDT Table. +**/ +STATIC CONST ACPI_PARSER GtdtParser[] = { + PARSE_ACPI_HEADER (&AcpiHdrInfo), + {L"CntControlBase Physical Address", 8, 36, L"0x%lx", NULL, NULL, + NULL, NULL}, + {L"Reserved", 4, 44, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Secure EL1 timer GSIV", 4, 48, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Secure EL1 timer FLAGS", 4, 52, L"0x%x", NULL, NULL, NULL, NULL}, + + {L"Non-Secure EL1 timer GSIV", 4, 56, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Non-Secure EL1 timer FLAGS", 4, 60, L"0x%x", NULL, NULL, NULL, NULL}, + + {L"Virtual timer GSIV", 4, 64, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Virtual timer FLAGS", 4, 68, L"0x%x", NULL, NULL, NULL, NULL}, + + {L"Non-Secure EL2 timer GSIV", 4, 72, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Non-Secure EL2 timer FLAGS", 4, 76, L"0x%x", NULL, NULL, NULL, NULL}, + + {L"CntReadBase Physical address", 8, 80, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Platform Timer Count", 4, 88, L"%d", NULL, + (VOID**)&GtdtPlatformTimerCount, NULL, NULL}, + {L"Platform Timer Offset", 4, 92, L"0x%x", NULL, + (VOID**)&GtdtPlatformTimerOffset, NULL, NULL}, + {L"Virtual EL2 Timer GSIV", 4, 96, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Virtual EL2 Timer Flags", 4, 100, L"0x%x", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the Platform timer header. +**/ +STATIC CONST ACPI_PARSER GtPlatformTimerHeaderParser[] = { + {L"Type", 1, 0, NULL, NULL, (VOID**)&PlatformTimerType, NULL, NULL}, + {L"Length", 2, 1, NULL, NULL, (VOID**)&PlatformTimerLength, NULL, NULL}, + {L"Reserved", 1, 3, NULL, NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the Platform GT Block. +**/ +STATIC CONST ACPI_PARSER GtBlockParser[] = { + {L"Type", 1, 0, L"%d", NULL, NULL, NULL, NULL}, + {L"Length", 2, 1, L"%d", NULL, NULL, NULL, NULL}, + {L"Reserved", 1, 3, L"%x", NULL, NULL, NULL, NULL}, + {L"Physical address (CntCtlBase)", 8, 4, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Timer Count", 4, 12, L"%d", NULL, (VOID**)&GtBlockTimerCount, + ValidateGtBlockTimerCount, NULL}, + {L"Timer Offset", 4, 16, L"%d", NULL, (VOID**)&GtBlockTimerOffset, NULL, + NULL} +}; + +/** + An ACPI_PARSER array describing the GT Block timer. +**/ +STATIC CONST ACPI_PARSER GtBlockTimerParser[] = { + {L"Frame Number", 1, 0, L"%d", NULL, NULL, ValidateGtFrameNumber, NULL}, + {L"Reserved", 3, 1, L"%x %x %x", Dump3Chars, NULL, NULL, NULL}, + {L"Physical address (CntBaseX)", 8, 4, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Physical address (CntEL0BaseX)", 8, 12, L"0x%lx", NULL, NULL, NULL, + NULL}, + {L"Physical Timer GSIV", 4, 20, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Physical Timer Flags", 4, 24, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Virtual Timer GSIV", 4, 28, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Virtual Timer Flags", 4, 32, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Common Flags", 4, 36, L"0x%x", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the Platform Watchdog. +**/ +STATIC CONST ACPI_PARSER SBSAGenericWatchdogParser[] = { + {L"Type", 1, 0, L"%d", NULL, NULL, NULL, NULL}, + {L"Length", 2, 1, L"%d", NULL, NULL, NULL, NULL}, + {L"Reserved", 1, 3, L"%x", NULL, NULL, NULL, NULL}, + {L"RefreshFrame Physical address", 8, 4, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"ControlFrame Physical address", 8, 12, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Watchdog Timer GSIV", 4, 20, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Watchdog Timer Flags", 4, 24, L"0x%x", NULL, NULL, NULL, NULL} +}; + +/** + This function parses the Platform GT Block. + + @param [in] Ptr Pointer to the start of the GT Block data. + @param [in] Length Length of the GT Block structure. +**/ +STATIC +VOID +DumpGTBlock ( + IN UINT8* Ptr, + IN UINT16 Length + ) +{ + UINT32 Index; + UINT32 Offset; + + ParseAcpi ( + TRUE, + 2, + "GT Block", + Ptr, + Length, + PARSER_PARAMS (GtBlockParser) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if ((GtBlockTimerCount == NULL) || + (GtBlockTimerOffset == NULL)) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient GT Block Structure length. Length = %d.\n", + Length + ); + return; + } + + Offset = *GtBlockTimerOffset; + Index = 0; + + // Parse the specified number of GT Block Timer Structures or the GT Block + // Structure buffer length. Whichever is minimum. + while ((Index++ < *GtBlockTimerCount) && + (Offset < Length)) { + Offset += ParseAcpi ( + TRUE, + 2, + "GT Block Timer", + Ptr + Offset, + Length - Offset, + PARSER_PARAMS (GtBlockTimerParser) + ); + } +} + +/** + This function parses the Platform Watchdog timer. + + @param [in] Ptr Pointer to the start of the watchdog timer data. + @param [in] Length Length of the watchdog timer structure. +**/ +STATIC +VOID +DumpWatchdogTimer ( + IN UINT8* Ptr, + IN UINT16 Length + ) +{ + ParseAcpi ( + TRUE, + 2, + "SBSA Generic Watchdog", + Ptr, + Length, + PARSER_PARAMS (SBSAGenericWatchdogParser) + ); +} + +/** + This function parses the ACPI GTDT table. + When trace is enabled this function parses the GTDT table and + traces the ACPI table fields. + + This function also parses the following platform timer structures: + - GT Block timer + - Watchdog timer + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiGtdt ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ) +{ + UINT32 Index; + UINT32 Offset; + UINT8* TimerPtr; + + if (!Trace) { + return; + } + + ParseAcpi ( + TRUE, + 0, + "GTDT", + Ptr, + AcpiTableLength, + PARSER_PARAMS (GtdtParser) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if ((GtdtPlatformTimerCount == NULL) || + (GtdtPlatformTimerOffset == NULL)) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient table length. AcpiTableLength = %d.\n", + AcpiTableLength + ); + return; + } + + TimerPtr = Ptr + *GtdtPlatformTimerOffset; + Offset = *GtdtPlatformTimerOffset; + Index = 0; + + // Parse the specified number of Platform Timer Structures or the GTDT + // buffer length. Whichever is minimum. + while ((Index++ < *GtdtPlatformTimerCount) && + (Offset < AcpiTableLength)) { + // Parse the Platform Timer Header to obtain Length and Type + ParseAcpi ( + FALSE, + 0, + NULL, + TimerPtr, + AcpiTableLength - Offset, + PARSER_PARAMS (GtPlatformTimerHeaderParser) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if ((PlatformTimerType == NULL) || + (PlatformTimerLength == NULL)) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient remaining table buffer length to read the " \ + L"Platform Timer Structure header. Length = %d.\n", + AcpiTableLength - Offset + ); + return; + } + + // Validate Platform Timer Structure length + if ((*PlatformTimerLength == 0) || + ((Offset + (*PlatformTimerLength)) > AcpiTableLength)) { + IncrementErrorCount (); + Print ( + L"ERROR: Invalid Platform Timer Structure length. " \ + L"Length = %d. Offset = %d. AcpiTableLength = %d.\n", + *PlatformTimerLength, + Offset, + AcpiTableLength + ); + return; + } + + switch (*PlatformTimerType) { + case EFI_ACPI_6_3_GTDT_GT_BLOCK: + DumpGTBlock (TimerPtr, *PlatformTimerLength); + break; + case EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG: + DumpWatchdogTimer (TimerPtr, *PlatformTimerLength); + break; + default: + IncrementErrorCount (); + Print ( + L"ERROR: Invalid Platform Timer Type = %d\n", + *PlatformTimerType + ); + break; + } // switch + + TimerPtr += *PlatformTimerLength; + Offset += *PlatformTimerLength; + } // while +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Hmat/HmatParser.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Hmat/HmatParser.c new file mode 100644 index 00000000..cbb9529d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Hmat/HmatParser.c @@ -0,0 +1,650 @@ +/** @file + HMAT table parser + + Copyright (c) 2020, Arm Limited. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - ACPI 6.3 Specification - January 2019 + + @par Glossary: + - MPDA - Memory Proximity Domain Attributes + - SLLBI - System Locality Latency and Bandwidth Information + - MSCI - Memory Side Cache Information + - Dom - Domain +**/ + +#include +#include +#include +#include "AcpiParser.h" +#include "AcpiView.h" + +// Maximum Memory Domain matrix print size. +#define MAX_MEMORY_DOMAIN_TARGET_PRINT_MATRIX 10 + +// Local variables +STATIC CONST UINT16* HmatStructureType; +STATIC CONST UINT32* HmatStructureLength; + +STATIC CONST UINT32* NumberInitiatorProximityDomain; +STATIC CONST UINT32* NumberTargetProximityDomain; +STATIC CONST +EFI_ACPI_6_3_HMAT_STRUCTURE_SYSTEM_LOCALITY_LATENCY_AND_BANDWIDTH_INFO_FLAGS* +SllbiFlags; + +STATIC CONST UINT8* SllbiDataType; +STATIC CONST UINT16* NumberSMBIOSHandles; + +STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo; + +/** + Names of System Locality Latency Bandwidth Information (SLLBI) data types +**/ +STATIC CONST CHAR16* SllbiNames[] = { + L"Access %sLatency%s", + L"Read %sLatency%s", + L"Write %sLatency%s", + L"Access %sBandwidth%s", + L"Read %sBandwidth%s", + L"Write %sBandwidth%s" +}; + +/** + This function validates the Cache Attributes field. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateCacheAttributes ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + EFI_ACPI_6_3_HMAT_STRUCTURE_MEMORY_SIDE_CACHE_INFO_CACHE_ATTRIBUTES* + Attributes; + + Attributes = + (EFI_ACPI_6_3_HMAT_STRUCTURE_MEMORY_SIDE_CACHE_INFO_CACHE_ATTRIBUTES*)Ptr; + + if (Attributes->TotalCacheLevels > 0x3) { + IncrementErrorCount (); + Print ( + L"\nERROR: Attributes bits [3:0] have invalid value: 0x%x", + Attributes->TotalCacheLevels + ); + } + if (Attributes->CacheLevel > 0x3) { + IncrementErrorCount (); + Print ( + L"\nERROR: Attributes bits [7:4] have invalid value: 0x%x", + Attributes->CacheLevel + ); + } + if (Attributes->CacheAssociativity > 0x2) { + IncrementErrorCount (); + Print ( + L"\nERROR: Attributes bits [11:8] have invalid value: 0x%x", + Attributes->CacheAssociativity + ); + } + if (Attributes->WritePolicy > 0x2) { + IncrementErrorCount (); + Print ( + L"\nERROR: Attributes bits [15:12] have invalid value: 0x%x", + Attributes->WritePolicy + ); + } +} + +/** + Dumps the cache attributes field + + @param [in] Format Optional format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +STATIC +VOID +EFIAPI +DumpCacheAttributes ( + IN CONST CHAR16* Format OPTIONAL, + IN UINT8* Ptr + ) +{ + EFI_ACPI_6_3_HMAT_STRUCTURE_MEMORY_SIDE_CACHE_INFO_CACHE_ATTRIBUTES* + Attributes; + + Attributes = + (EFI_ACPI_6_3_HMAT_STRUCTURE_MEMORY_SIDE_CACHE_INFO_CACHE_ATTRIBUTES*)Ptr; + + Print (L"\n"); + PrintFieldName (4, L"Total Cache Levels"); + Print (L"%d\n", Attributes->TotalCacheLevels); + PrintFieldName (4, L"Cache Level"); + Print (L"%d\n", Attributes->CacheLevel); + PrintFieldName (4, L"Cache Associativity"); + Print (L"%d\n", Attributes->CacheAssociativity); + PrintFieldName (4, L"Write Policy"); + Print (L"%d\n", Attributes->WritePolicy); + PrintFieldName (4, L"Cache Line Size"); + Print (L"%d\n", Attributes->CacheLineSize); +} + +/** + An ACPI_PARSER array describing the ACPI HMAT Table. +*/ +STATIC CONST ACPI_PARSER HmatParser[] = { + PARSE_ACPI_HEADER (&AcpiHdrInfo), + {L"Reserved", 4, 36, NULL, NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the HMAT structure header. +*/ +STATIC CONST ACPI_PARSER HmatStructureHeaderParser[] = { + {L"Type", 2, 0, NULL, NULL, (VOID**)&HmatStructureType, NULL, NULL}, + {L"Reserved", 2, 2, NULL, NULL, NULL, NULL, NULL}, + {L"Length", 4, 4, NULL, NULL, (VOID**)&HmatStructureLength, NULL, NULL} +}; + +/** + An ACPI PARSER array describing the Memory Proximity Domain Attributes + Structure - Type 0. +*/ +STATIC CONST ACPI_PARSER MemProximityDomainAttributeParser[] = { + {L"Type", 2, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Length", 4, 4, L"%d", NULL, NULL, NULL, NULL}, + {L"Flags", 2, 8, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 2, 10, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Proximity Dom for initiator", 4, 12, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Proximity Dom for memory", 4, 16, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 4, 20, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 8, 24, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Reserved", 8, 32, L"0x%lx", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI PARSER array describing the System Locality Latency and Bandwidth + Information Structure - Type 1. +*/ +STATIC CONST ACPI_PARSER SllbiParser[] = { + {L"Type", 2, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Length", 4, 4, L"%d", NULL, NULL, NULL, NULL}, + {L"Flags", 1, 8, L"0x%x", NULL, (VOID**)&SllbiFlags, NULL, NULL}, + {L"Data type", 1, 9, L"0x%x", NULL, (VOID**)&SllbiDataType, NULL, NULL}, + {L"Reserved", 2, 10, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Initiator Proximity Dom Count", 4, 12, L"%d", NULL, + (VOID**)&NumberInitiatorProximityDomain, NULL, NULL}, + {L"Target Proximity Dom Count", 4, 16, L"%d", NULL, + (VOID**)&NumberTargetProximityDomain, NULL, NULL}, + {L"Reserved", 4, 20, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Entry Base Unit", 8, 24, L"0x%lx", NULL, NULL, NULL, NULL} + // initiator Proximity Domain list ... + // target Proximity Domain list ... + // Latency/Bandwidth matrix ... +}; + +/** + An ACPI PARSER array describing the Memory Side Cache Information + Structure - Type 2. +*/ +STATIC CONST ACPI_PARSER MemSideCacheInfoParser[] = { + {L"Type", 2, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Length", 4, 4, L"%d", NULL, NULL, NULL, NULL}, + {L"Proximity Dom for memory", 4, 8, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 4, 12, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Memory Side Cache Size", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Cache Attributes", 4, 24, NULL, DumpCacheAttributes, NULL, + ValidateCacheAttributes, NULL}, + {L"Reserved", 2, 28, L"0x%x", NULL, NULL, NULL, NULL}, + {L"SMBIOS Handle Count", 2, 30, L"%d", NULL, + (VOID**)&NumberSMBIOSHandles, NULL, NULL} + // SMBIOS handles List ... +}; + +/** + This function parses the Memory Proximity Domain Attributes + Structure (Type 0). + + @param [in] Ptr Pointer to the start of the Memory Proximity Domain + Attributes Structure data. + @param [in] Length Length of the Memory Proximity Domain Attributes + Structure. +**/ +STATIC +VOID +DumpMpda ( + IN UINT8* Ptr, + IN UINT32 Length + ) +{ + ParseAcpi ( + TRUE, + 2, + "Memory Proximity Domain Attributes Structure", + Ptr, + Length, + PARSER_PARAMS (MemProximityDomainAttributeParser) + ); +} + +/** + This function parses the System Locality Latency and Bandwidth Information + Structure (Type 1). + + @param [in] Ptr Pointer to the start of the System Locality Latency and + Bandwidth Information Structure data. + @param [in] Length Length of the System Locality Latency and Bandwidth + Information Structure. +**/ +STATIC +VOID +DumpSllbi ( + IN UINT8* Ptr, + IN UINT32 Length + ) +{ + CONST UINT32* InitiatorProximityDomainList; + CONST UINT32* TargetProximityDomainList; + CONST UINT16* LatencyBandwidthMatrix; + UINT32 Offset; + CHAR16 Buffer[OUTPUT_FIELD_COLUMN_WIDTH]; + CHAR16 SecondBuffer[OUTPUT_FIELD_COLUMN_WIDTH]; + UINT32 RequiredTableSize; + UINT32 Index; + UINT32 IndexInitiator; + UINT32 IndexTarget; + UINT32 TargetStartOffset; + + Offset = ParseAcpi ( + TRUE, + 2, + "System Locality Latency and Bandwidth Information Structure", + Ptr, + Length, + PARSER_PARAMS (SllbiParser) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if ((SllbiFlags == NULL) || + (SllbiDataType == NULL) || + (NumberInitiatorProximityDomain == NULL) || + (NumberTargetProximityDomain == NULL)) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient remaining table buffer length to read the " \ + L"SLLBI structure header. Length = %d.\n", + Length + ); + return; + } + + RequiredTableSize = (*NumberInitiatorProximityDomain * sizeof (UINT32)) + + (*NumberTargetProximityDomain * sizeof (UINT32)) + + (*NumberInitiatorProximityDomain * + *NumberTargetProximityDomain * sizeof (UINT16)) + + Offset; + + if (RequiredTableSize > Length) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient System Locality Latency and Bandwidth" \ + L"Information Structure length. TableLength = %d. " \ + L"RequiredTableLength = %d.\n", + Length, + RequiredTableSize + ); + return; + } + + InitiatorProximityDomainList = (UINT32*) (Ptr + Offset); + TargetProximityDomainList = InitiatorProximityDomainList + + *NumberInitiatorProximityDomain; + LatencyBandwidthMatrix = (UINT16*) (TargetProximityDomainList + + *NumberTargetProximityDomain); + + // Display each element of the Initiator Proximity Domain list + for (Index = 0; Index < *NumberInitiatorProximityDomain; Index++) { + UnicodeSPrint ( + Buffer, + sizeof (Buffer), + L"Initiator Proximity Dom [%d]", + Index + ); + + PrintFieldName (4, Buffer); + Print ( + L"0x%x\n", + InitiatorProximityDomainList[Index] + ); + } + + // Display each element of the Target Proximity Domain list + for (Index = 0; Index < *NumberTargetProximityDomain; Index++) { + UnicodeSPrint ( + Buffer, + sizeof (Buffer), + L"Target Proximity Dom [%d]", + Index + ); + + PrintFieldName (4, Buffer); + Print ( + L"0x%x\n", + TargetProximityDomainList[Index] + ); + } + + // Create base name depending on Data Type in this Structure + if (*SllbiDataType >= ARRAY_SIZE (SllbiNames)) { + IncrementErrorCount (); + Print (L"Error: Unkown Data Type. DataType = 0x%x.\n", *SllbiDataType); + return; + } + StrCpyS (Buffer, sizeof (Buffer), SllbiNames[*SllbiDataType]); + + // Adjust base name depending on Memory Hierarchy in this Structure + switch (SllbiFlags->MemoryHierarchy) { + case 0: + UnicodeSPrint ( + SecondBuffer, + sizeof (SecondBuffer), + Buffer, + L"", + L"%s" + ); + break; + case 1: + case 2: + case 3: + UnicodeSPrint ( + SecondBuffer, + sizeof (SecondBuffer), + Buffer, + L"Hit ", + L"%s" + ); + break; + default: + IncrementErrorCount (); + Print ( + L"Error: Invalid Memory Hierarchy. MemoryHierarchy = %d.\n", + SllbiFlags->MemoryHierarchy + ); + return; + + } // switch + + if (*NumberTargetProximityDomain <= MAX_MEMORY_DOMAIN_TARGET_PRINT_MATRIX) { + // Display the latency/bandwidth matrix as a matrix + UnicodeSPrint ( + Buffer, + sizeof (Buffer), + SecondBuffer, + L"" + ); + PrintFieldName (4, Buffer); + + Print (L"\n Target : X-axis (Horizontal)"); + Print (L"\n Initiator : Y-axis (Vertical)"); + Print (L"\n |"); + + for (IndexTarget = 0; + IndexTarget < *NumberTargetProximityDomain; + IndexTarget++) { + Print (L" %2d", IndexTarget); + } + + Print (L"\n ---+"); + for (IndexTarget = 0; + IndexTarget < *NumberTargetProximityDomain; + IndexTarget++) { + Print (L"------"); + } + Print (L"\n"); + + TargetStartOffset = 0; + for (IndexInitiator = 0; + IndexInitiator < *NumberInitiatorProximityDomain; + IndexInitiator++) { + Print (L" %2d |", IndexInitiator); + for (IndexTarget = 0; + IndexTarget < *NumberTargetProximityDomain; + IndexTarget++) { + Print ( + L" %5d", + LatencyBandwidthMatrix[TargetStartOffset + IndexTarget] + ); + } // for Target + Print (L"\n"); + TargetStartOffset += (*NumberTargetProximityDomain); + } // for Initiator + Print (L"\n"); + } else { + // Display the latency/bandwidth matrix as a list + UnicodeSPrint ( + Buffer, + sizeof (Buffer), + SecondBuffer, + L" [%d][%d]" + ); + + TargetStartOffset = 0; + for (IndexInitiator = 0; + IndexInitiator < *NumberInitiatorProximityDomain; + IndexInitiator++) { + for (IndexTarget = 0; + IndexTarget < *NumberTargetProximityDomain; + IndexTarget++) { + UnicodeSPrint ( + SecondBuffer, + sizeof (SecondBuffer), + Buffer, + IndexInitiator, + IndexTarget + ); + + PrintFieldName (4, SecondBuffer); + Print ( + L"%d\n", + LatencyBandwidthMatrix[TargetStartOffset + IndexTarget] + ); + } // for Target + TargetStartOffset += (*NumberTargetProximityDomain); + } // for Initiator + } +} + +/** + This function parses the Memory Side Cache Information Structure (Type 2). + + @param [in] Ptr Pointer to the start of the Memory Side Cache Information + Structure data. + @param [in] Length Length of the Memory Side Cache Information Structure. +**/ +STATIC +VOID +DumpMsci ( + IN UINT8* Ptr, + IN UINT32 Length + ) +{ + CONST UINT16* SMBIOSHandlesList; + CHAR16 Buffer[OUTPUT_FIELD_COLUMN_WIDTH]; + UINT32 Offset; + UINT16 Index; + + Offset = ParseAcpi ( + TRUE, + 2, + "Memory Side Cache Information Structure", + Ptr, + Length, + PARSER_PARAMS (MemSideCacheInfoParser) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if (NumberSMBIOSHandles == NULL) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient remaining table buffer length to read the " \ + L"MSCI structure header. Length = %d.\n", + Length + ); + return; + } + + if ((*NumberSMBIOSHandles * sizeof (UINT16)) > (Length - Offset)) { + IncrementErrorCount (); + Print ( + L"ERROR: Invalid Number of SMBIOS Handles. SMBIOSHandlesCount = %d." \ + L"RemainingBufferLength = %d.\n", + *NumberSMBIOSHandles, + Length - Offset + ); + return; + } + + SMBIOSHandlesList = (UINT16*) (Ptr + Offset); + + for (Index = 0; Index < *NumberSMBIOSHandles; Index++) { + UnicodeSPrint ( + Buffer, + sizeof (Buffer), + L"SMBIOS Handles [%d]", + Index + ); + + PrintFieldName (4, Buffer); + Print ( + L"0x%x\n", + SMBIOSHandlesList[Index] + ); + } +} + +/** + This function parses the ACPI HMAT table. + When trace is enabled this function parses the HMAT table and + traces the ACPI table fields. + + This function parses the following HMAT structures: + - Memory Proximity Domain Attributes Structure (Type 0) + - System Locality Latency and Bandwidth Info Structure (Type 1) + - Memory Side Cache Info structure (Type 2) + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiHmat ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ) +{ + UINT32 Offset; + UINT8* HmatStructurePtr; + + if (!Trace) { + return; + } + + Offset = ParseAcpi ( + Trace, + 0, + "HMAT", + Ptr, + AcpiTableLength, + PARSER_PARAMS (HmatParser) + ); + + HmatStructurePtr = Ptr + Offset; + + while (Offset < AcpiTableLength) { + // Parse HMAT Structure Header to obtain Type and Length. + ParseAcpi ( + FALSE, + 0, + NULL, + HmatStructurePtr, + AcpiTableLength - Offset, + PARSER_PARAMS (HmatStructureHeaderParser) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if ((HmatStructureType == NULL) || + (HmatStructureLength == NULL)) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient remaining table buffer length to read the " \ + L"HMAT structure header. Length = %d.\n", + AcpiTableLength - Offset + ); + return; + } + + // Validate HMAT Structure length. + if ((*HmatStructureLength == 0) || + ((Offset + (*HmatStructureLength)) > AcpiTableLength)) { + IncrementErrorCount (); + Print ( + L"ERROR: Invalid HMAT Structure length. " \ + L"Length = %d. Offset = %d. AcpiTableLength = %d.\n", + *HmatStructureLength, + Offset, + AcpiTableLength + ); + return; + } + + switch (*HmatStructureType) { + case EFI_ACPI_6_3_HMAT_TYPE_MEMORY_PROXIMITY_DOMAIN_ATTRIBUTES: + DumpMpda ( + HmatStructurePtr, + *HmatStructureLength + ); + break; + case EFI_ACPI_6_3_HMAT_TYPE_SYSTEM_LOCALITY_LATENCY_AND_BANDWIDTH_INFO: + DumpSllbi ( + HmatStructurePtr, + *HmatStructureLength + ); + break; + case EFI_ACPI_6_3_HMAT_TYPE_MEMORY_SIDE_CACHE_INFO: + DumpMsci ( + HmatStructurePtr, + *HmatStructureLength + ); + break; + default: + IncrementErrorCount (); + Print ( + L"ERROR: Unknown HMAT structure:" + L" Type = %d, Length = %d\n", + *HmatStructureType, + *HmatStructureLength + ); + break; + } // switch + + HmatStructurePtr += *HmatStructureLength; + Offset += *HmatStructureLength; + } // while +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Iort/IortParser.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Iort/IortParser.c new file mode 100644 index 00000000..1cd8b4f4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Iort/IortParser.c @@ -0,0 +1,764 @@ +/** @file + IORT table parser + + Copyright (c) 2016 - 2020, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - IO Remapping Table, Platform Design Document, Revision D, March 2018 +**/ + +#include +#include +#include +#include "AcpiParser.h" +#include "AcpiTableParser.h" +#include "AcpiViewConfig.h" + +// Local variables +STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo; + +STATIC CONST UINT32* IortNodeCount; +STATIC CONST UINT32* IortNodeOffset; + +STATIC CONST UINT8* IortNodeType; +STATIC CONST UINT16* IortNodeLength; +STATIC CONST UINT32* IortIdMappingCount; +STATIC CONST UINT32* IortIdMappingOffset; + +STATIC CONST UINT32* InterruptContextCount; +STATIC CONST UINT32* InterruptContextOffset; +STATIC CONST UINT32* PmuInterruptCount; +STATIC CONST UINT32* PmuInterruptOffset; + +STATIC CONST UINT32* ItsCount; + +/** + This function validates the ID Mapping array count for the ITS node. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateItsIdMappingCount ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + if (*(UINT32*)Ptr != 0) { + IncrementErrorCount (); + Print (L"\nERROR: IORT ID Mapping count must be zero."); + } +} + +/** + This function validates the ID Mapping array count for the Performance + Monitoring Counter Group (PMCG) node. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidatePmcgIdMappingCount ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + if (*(UINT32*)Ptr > 1) { + IncrementErrorCount (); + Print (L"\nERROR: IORT ID Mapping count must not be greater than 1."); + } +} + +/** + This function validates the ID Mapping array offset for the ITS node. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateItsIdArrayReference ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + if (*(UINT32*)Ptr != 0) { + IncrementErrorCount (); + Print (L"\nERROR: IORT ID Mapping offset must be zero."); + } +} + +/** + Helper Macro for populating the IORT Node header in the ACPI_PARSER array. + + @param [out] ValidateIdMappingCount Optional pointer to a function for + validating the ID Mapping count. + @param [out] ValidateIdArrayReference Optional pointer to a function for + validating the ID Array reference. +**/ +#define PARSE_IORT_NODE_HEADER(ValidateIdMappingCount, \ + ValidateIdArrayReference) \ + { L"Type", 1, 0, L"%d", NULL, (VOID**)&IortNodeType, NULL, NULL }, \ + { L"Length", 2, 1, L"%d", NULL, (VOID**)&IortNodeLength, NULL, NULL }, \ + { L"Revision", 1, 3, L"%d", NULL, NULL, NULL, NULL }, \ + { L"Reserved", 4, 4, L"0x%x", NULL, NULL, NULL, NULL }, \ + { L"Number of ID mappings", 4, 8, L"%d", NULL, \ + (VOID**)&IortIdMappingCount, ValidateIdMappingCount, NULL }, \ + { L"Reference to ID Array", 4, 12, L"0x%x", NULL, \ + (VOID**)&IortIdMappingOffset, ValidateIdArrayReference, NULL } + +/** + An ACPI_PARSER array describing the ACPI IORT Table +**/ +STATIC CONST ACPI_PARSER IortParser[] = { + PARSE_ACPI_HEADER (&AcpiHdrInfo), + {L"Number of IORT Nodes", 4, 36, L"%d", NULL, + (VOID**)&IortNodeCount, NULL, NULL}, + {L"Offset to Array of IORT Nodes", 4, 40, L"0x%x", NULL, + (VOID**)&IortNodeOffset, NULL, NULL}, + {L"Reserved", 4, 44, L"0x%x", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the IORT node header structure. +**/ +STATIC CONST ACPI_PARSER IortNodeHeaderParser[] = { + PARSE_IORT_NODE_HEADER (NULL, NULL) +}; + +/** + An ACPI_PARSER array describing the IORT SMMUv1/2 node. +**/ +STATIC CONST ACPI_PARSER IortNodeSmmuV1V2Parser[] = { + PARSE_IORT_NODE_HEADER (NULL, NULL), + {L"Base Address", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Span", 8, 24, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Model", 4, 32, L"%d", NULL, NULL, NULL, NULL}, + {L"Flags", 4, 36, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reference to Global Interrupt Array", 4, 40, L"0x%x", NULL, NULL, NULL, + NULL}, + {L"Number of context interrupts", 4, 44, L"%d", NULL, + (VOID**)&InterruptContextCount, NULL, NULL}, + {L"Reference to Context Interrupt Array", 4, 48, L"0x%x", NULL, + (VOID**)&InterruptContextOffset, NULL, NULL}, + {L"Number of PMU Interrupts", 4, 52, L"%d", NULL, + (VOID**)&PmuInterruptCount, NULL, NULL}, + {L"Reference to PMU Interrupt Array", 4, 56, L"0x%x", NULL, + (VOID**)&PmuInterruptOffset, NULL, NULL}, + + // Interrupt Array + {L"SMMU_NSgIrpt", 4, 60, L"0x%x", NULL, NULL, NULL, NULL}, + {L"SMMU_NSgIrpt interrupt flags", 4, 64, L"0x%x", NULL, NULL, NULL, NULL}, + {L"SMMU_NSgCfgIrpt", 4, 68, L"0x%x", NULL, NULL, NULL, NULL}, + {L"SMMU_NSgCfgIrpt interrupt flags", 4, 72, L"0x%x", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the SMMUv1/2 Node Interrupt Array. +**/ +STATIC CONST ACPI_PARSER InterruptArrayParser[] = { + {L"Interrupt GSIV", 4, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Flags", 4, 4, L"0x%x", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the IORT ID Mapping. +**/ +STATIC CONST ACPI_PARSER IortNodeIdMappingParser[] = { + {L"Input base", 4, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Number of IDs", 4, 4, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Output base", 4, 8, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Output reference", 4, 12, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Flags", 4, 16, L"0x%x", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the IORT SMMUv3 node. +**/ +STATIC CONST ACPI_PARSER IortNodeSmmuV3Parser[] = { + PARSE_IORT_NODE_HEADER (NULL, NULL), + {L"Base Address", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Flags", 4, 24, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 4, 28, L"0x%x", NULL, NULL, NULL, NULL}, + {L"VATOS Address", 8, 32, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Model", 4, 40, L"%d", NULL, NULL, NULL, NULL}, + {L"Event", 4, 44, L"0x%x", NULL, NULL, NULL, NULL}, + {L"PRI", 4, 48, L"0x%x", NULL, NULL, NULL, NULL}, + {L"GERR", 4, 52, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Sync", 4, 56, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Proximity domain", 4, 60, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Device ID mapping index", 4, 64, L"%d", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the IORT ITS node. +**/ +STATIC CONST ACPI_PARSER IortNodeItsParser[] = { + PARSE_IORT_NODE_HEADER ( + ValidateItsIdMappingCount, + ValidateItsIdArrayReference + ), + {L"Number of ITSs", 4, 16, L"%d", NULL, (VOID**)&ItsCount, NULL} +}; + +/** + An ACPI_PARSER array describing the ITS ID. +**/ +STATIC CONST ACPI_PARSER ItsIdParser[] = { + { L"GIC ITS Identifier", 4, 0, L"%d", NULL, NULL, NULL } +}; + +/** + An ACPI_PARSER array describing the IORT Names Component node. +**/ +STATIC CONST ACPI_PARSER IortNodeNamedComponentParser[] = { + PARSE_IORT_NODE_HEADER (NULL, NULL), + {L"Node Flags", 4, 16, L"%d", NULL, NULL, NULL, NULL}, + {L"Memory access properties", 8, 20, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Device memory address size limit", 1, 28, L"%d", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the IORT Root Complex node. +**/ +STATIC CONST ACPI_PARSER IortNodeRootComplexParser[] = { + PARSE_IORT_NODE_HEADER (NULL, NULL), + {L"Memory access properties", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"ATS Attribute", 4, 24, L"0x%x", NULL, NULL, NULL, NULL}, + {L"PCI Segment number", 4, 28, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Memory access size limit", 1, 32, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 3, 33, L"%x %x %x", Dump3Chars, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the IORT PMCG node. +**/ +STATIC CONST ACPI_PARSER IortNodePmcgParser[] = { + PARSE_IORT_NODE_HEADER (ValidatePmcgIdMappingCount, NULL), + {L"Page 0 Base Address", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Overflow interrupt GSIV", 4, 24, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Node reference", 4, 28, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Page 1 Base Address", 8, 32, L"0x%lx", NULL, NULL, NULL, NULL} +}; + +/** + This function parses the IORT Node Id Mapping array. + + @param [in] Ptr Pointer to the start of the ID mapping array. + @param [in] Length Length of the buffer. + @param [in] MappingCount The ID Mapping count. +**/ +STATIC +VOID +DumpIortNodeIdMappings ( + IN UINT8* Ptr, + IN UINT32 Length, + IN UINT32 MappingCount + ) +{ + UINT32 Index; + UINT32 Offset; + CHAR8 Buffer[40]; // Used for AsciiName param of ParseAcpi + + Index = 0; + Offset = 0; + + while ((Index < MappingCount) && + (Offset < Length)) { + AsciiSPrint ( + Buffer, + sizeof (Buffer), + "ID Mapping [%d]", + Index + ); + Offset += ParseAcpi ( + TRUE, + 4, + Buffer, + Ptr + Offset, + Length - Offset, + PARSER_PARAMS (IortNodeIdMappingParser) + ); + Index++; + } +} + +/** + This function parses the IORT SMMUv1/2 node. + + @param [in] Ptr Pointer to the start of the buffer. + @param [in] Length Length of the buffer. + @param [in] MappingCount The ID Mapping count. + @param [in] MappingOffset The offset of the ID Mapping array + from the start of the IORT table. +**/ +STATIC +VOID +DumpIortNodeSmmuV1V2 ( + IN UINT8* Ptr, + IN UINT16 Length, + IN UINT32 MappingCount, + IN UINT32 MappingOffset + ) +{ + UINT32 Index; + UINT32 Offset; + CHAR8 Buffer[50]; // Used for AsciiName param of ParseAcpi + + ParseAcpi ( + TRUE, + 2, + "SMMUv1 or SMMUv2 Node", + Ptr, + Length, + PARSER_PARAMS (IortNodeSmmuV1V2Parser) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if ((InterruptContextCount == NULL) || + (InterruptContextOffset == NULL) || + (PmuInterruptCount == NULL) || + (PmuInterruptOffset == NULL)) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient SMMUv1/2 node length. Length = %d\n", + Length + ); + return; + } + + Offset = *InterruptContextOffset; + Index = 0; + + while ((Index < *InterruptContextCount) && + (Offset < Length)) { + AsciiSPrint ( + Buffer, + sizeof (Buffer), + "Context Interrupts Array [%d]", + Index + ); + Offset += ParseAcpi ( + TRUE, + 4, + Buffer, + Ptr + Offset, + Length - Offset, + PARSER_PARAMS (InterruptArrayParser) + ); + Index++; + } + + Offset = *PmuInterruptOffset; + Index = 0; + + while ((Index < *PmuInterruptCount) && + (Offset < Length)) { + AsciiSPrint ( + Buffer, + sizeof (Buffer), + "PMU Interrupts Array [%d]", + Index + ); + Offset += ParseAcpi ( + TRUE, + 4, + Buffer, + Ptr + Offset, + Length - Offset, + PARSER_PARAMS (InterruptArrayParser) + ); + Index++; + } + + DumpIortNodeIdMappings ( + Ptr + MappingOffset, + Length - MappingOffset, + MappingCount + ); +} + +/** + This function parses the IORT SMMUv3 node. + + @param [in] Ptr Pointer to the start of the buffer. + @param [in] Length Length of the buffer. + @param [in] MappingCount The ID Mapping count. + @param [in] MappingOffset The offset of the ID Mapping array + from the start of the IORT table. +**/ +STATIC +VOID +DumpIortNodeSmmuV3 ( + IN UINT8* Ptr, + IN UINT16 Length, + IN UINT32 MappingCount, + IN UINT32 MappingOffset + ) +{ + ParseAcpi ( + TRUE, + 2, + "SMMUV3 Node", + Ptr, + Length, + PARSER_PARAMS (IortNodeSmmuV3Parser) + ); + + DumpIortNodeIdMappings ( + Ptr + MappingOffset, + Length - MappingOffset, + MappingCount + ); +} + +/** + This function parses the IORT ITS node. + + @param [in] Ptr Pointer to the start of the buffer. + @param [in] Length Length of the buffer. +**/ +STATIC +VOID +DumpIortNodeIts ( + IN UINT8* Ptr, + IN UINT16 Length + ) +{ + UINT32 Offset; + UINT32 Index; + CHAR8 Buffer[80]; // Used for AsciiName param of ParseAcpi + + Offset = ParseAcpi ( + TRUE, + 2, + "ITS Node", + Ptr, + Length, + PARSER_PARAMS (IortNodeItsParser) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if (ItsCount == NULL) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient ITS group length. Length = %d.\n", + Length + ); + return; + } + + Index = 0; + + while ((Index < *ItsCount) && + (Offset < Length)) { + AsciiSPrint ( + Buffer, + sizeof (Buffer), + "GIC ITS Identifier Array [%d]", + Index + ); + Offset += ParseAcpi ( + TRUE, + 4, + Buffer, + Ptr + Offset, + Length - Offset, + PARSER_PARAMS (ItsIdParser) + ); + Index++; + } + + // Note: ITS does not have the ID Mappings Array + +} + +/** + This function parses the IORT Named Component node. + + @param [in] Ptr Pointer to the start of the buffer. + @param [in] Length Length of the buffer. + @param [in] MappingCount The ID Mapping count. + @param [in] MappingOffset The offset of the ID Mapping array + from the start of the IORT table. +**/ +STATIC +VOID +DumpIortNodeNamedComponent ( + IN UINT8* Ptr, + IN UINT16 Length, + IN UINT32 MappingCount, + IN UINT32 MappingOffset + ) +{ + UINT32 Offset; + + Offset = ParseAcpi ( + TRUE, + 2, + "Named Component Node", + Ptr, + Length, + PARSER_PARAMS (IortNodeNamedComponentParser) + ); + + // Estimate the Device Name length + PrintFieldName (2, L"Device Object Name"); + + while ((*(Ptr + Offset) != 0) && + (Offset < Length)) { + Print (L"%c", *(Ptr + Offset)); + Offset++; + } + Print (L"\n"); + + DumpIortNodeIdMappings ( + Ptr + MappingOffset, + Length - MappingOffset, + MappingCount + ); +} + +/** + This function parses the IORT Root Complex node. + + @param [in] Ptr Pointer to the start of the buffer. + @param [in] Length Length of the buffer. + @param [in] MappingCount The ID Mapping count. + @param [in] MappingOffset The offset of the ID Mapping array + from the start of the IORT table. +**/ +STATIC +VOID +DumpIortNodeRootComplex ( + IN UINT8* Ptr, + IN UINT16 Length, + IN UINT32 MappingCount, + IN UINT32 MappingOffset + ) +{ + ParseAcpi ( + TRUE, + 2, + "Root Complex Node", + Ptr, + Length, + PARSER_PARAMS (IortNodeRootComplexParser) + ); + + DumpIortNodeIdMappings ( + Ptr + MappingOffset, + Length - MappingOffset, + MappingCount + ); +} + +/** + This function parses the IORT PMCG node. + + @param [in] Ptr Pointer to the start of the buffer. + @param [in] Length Length of the buffer. + @param [in] MappingCount The ID Mapping count. + @param [in] MappingOffset The offset of the ID Mapping array + from the start of the IORT table. +**/ +STATIC +VOID +DumpIortNodePmcg ( + IN UINT8* Ptr, + IN UINT16 Length, + IN UINT32 MappingCount, + IN UINT32 MappingOffset +) +{ + ParseAcpi ( + TRUE, + 2, + "PMCG Node", + Ptr, + Length, + PARSER_PARAMS (IortNodePmcgParser) + ); + + DumpIortNodeIdMappings ( + Ptr + MappingOffset, + Length - MappingOffset, + MappingCount + ); +} + +/** + This function parses the ACPI IORT table. + When trace is enabled this function parses the IORT table and traces the ACPI fields. + + This function also parses the following nodes: + - ITS Group + - Named Component + - Root Complex + - SMMUv1/2 + - SMMUv3 + - PMCG + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiIort ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ) +{ + UINT32 Offset; + UINT32 Index; + UINT8* NodePtr; + + if (!Trace) { + return; + } + + ParseAcpi ( + TRUE, + 0, + "IORT", + Ptr, + AcpiTableLength, + PARSER_PARAMS (IortParser) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if ((IortNodeCount == NULL) || + (IortNodeOffset == NULL)) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient table length. AcpiTableLength = %d.\n", + AcpiTableLength + ); + return; + } + + Offset = *IortNodeOffset; + NodePtr = Ptr + Offset; + Index = 0; + + // Parse the specified number of IORT nodes or the IORT table buffer length. + // Whichever is minimum. + while ((Index++ < *IortNodeCount) && + (Offset < AcpiTableLength)) { + // Parse the IORT Node Header + ParseAcpi ( + FALSE, + 0, + "IORT Node Header", + NodePtr, + AcpiTableLength - Offset, + PARSER_PARAMS (IortNodeHeaderParser) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if ((IortNodeType == NULL) || + (IortNodeLength == NULL) || + (IortIdMappingCount == NULL) || + (IortIdMappingOffset == NULL)) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient remaining table buffer length to read the " \ + L"IORT node header. Length = %d.\n", + AcpiTableLength - Offset + ); + return; + } + + // Validate IORT Node length + if ((*IortNodeLength == 0) || + ((Offset + (*IortNodeLength)) > AcpiTableLength)) { + IncrementErrorCount (); + Print ( + L"ERROR: Invalid IORT Node length. " \ + L"Length = %d. Offset = %d. AcpiTableLength = %d.\n", + *IortNodeLength, + Offset, + AcpiTableLength + ); + return; + } + + PrintFieldName (2, L"* Node Offset *"); + Print (L"0x%x\n", Offset); + + switch (*IortNodeType) { + case EFI_ACPI_IORT_TYPE_ITS_GROUP: + DumpIortNodeIts ( + NodePtr, + *IortNodeLength + ); + break; + case EFI_ACPI_IORT_TYPE_NAMED_COMP: + DumpIortNodeNamedComponent ( + NodePtr, + *IortNodeLength, + *IortIdMappingCount, + *IortIdMappingOffset + ); + break; + case EFI_ACPI_IORT_TYPE_ROOT_COMPLEX: + DumpIortNodeRootComplex ( + NodePtr, + *IortNodeLength, + *IortIdMappingCount, + *IortIdMappingOffset + ); + break; + case EFI_ACPI_IORT_TYPE_SMMUv1v2: + DumpIortNodeSmmuV1V2 ( + NodePtr, + *IortNodeLength, + *IortIdMappingCount, + *IortIdMappingOffset + ); + break; + case EFI_ACPI_IORT_TYPE_SMMUv3: + DumpIortNodeSmmuV3 ( + NodePtr, + *IortNodeLength, + *IortIdMappingCount, + *IortIdMappingOffset + ); + break; + case EFI_ACPI_IORT_TYPE_PMCG: + DumpIortNodePmcg ( + NodePtr, + *IortNodeLength, + *IortIdMappingCount, + *IortIdMappingOffset + ); + break; + + default: + IncrementErrorCount (); + Print (L"ERROR: Unsupported IORT Node type = %d\n", *IortNodeType); + } // switch + + NodePtr += (*IortNodeLength); + Offset += (*IortNodeLength); + } // while +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Madt/MadtParser.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Madt/MadtParser.c new file mode 100644 index 00000000..438826ce --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Madt/MadtParser.c @@ -0,0 +1,374 @@ +/** @file + MADT table parser + + Copyright (c) 2016 - 2020, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - ACPI 6.3 Specification - January 2019 + - Arm Generic Interrupt Controller Architecture Specification, + GIC architecture version 3 and version 4, issue E + - Arm Server Base System Architecture 5.0 +**/ + +#include +#include +#include "AcpiParser.h" +#include "AcpiTableParser.h" +#include "AcpiViewConfig.h" +#include "MadtParser.h" + +// Local Variables +STATIC CONST UINT8* MadtInterruptControllerType; +STATIC CONST UINT8* MadtInterruptControllerLength; +STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo; + +/** + This function validates the System Vector Base in the GICD. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateGICDSystemVectorBase ( + IN UINT8* Ptr, + IN VOID* Context +) +{ + if (*(UINT32*)Ptr != 0) { + IncrementErrorCount (); + Print ( + L"\nERROR: System Vector Base must be zero." + ); + } +} + +/** + This function validates the SPE Overflow Interrupt in the GICC. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateSpeOverflowInterrupt ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + UINT16 SpeOverflowInterrupt; + + SpeOverflowInterrupt = *(UINT16*)Ptr; + + // SPE not supported by this processor + if (SpeOverflowInterrupt == 0) { + return; + } + + if ((SpeOverflowInterrupt < ARM_PPI_ID_MIN) || + ((SpeOverflowInterrupt > ARM_PPI_ID_MAX) && + (SpeOverflowInterrupt < ARM_PPI_ID_EXTENDED_MIN)) || + (SpeOverflowInterrupt > ARM_PPI_ID_EXTENDED_MAX)) { + IncrementErrorCount (); + Print ( + L"\nERROR: SPE Overflow Interrupt ID of %d is not in the allowed PPI ID " + L"ranges of %d-%d or %d-%d (for GICv3.1 or later).", + SpeOverflowInterrupt, + ARM_PPI_ID_MIN, + ARM_PPI_ID_MAX, + ARM_PPI_ID_EXTENDED_MIN, + ARM_PPI_ID_EXTENDED_MAX + ); + } else if (SpeOverflowInterrupt != ARM_PPI_ID_PMBIRQ) { + IncrementWarningCount(); + Print ( + L"\nWARNING: SPE Overflow Interrupt ID of %d is not compliant with SBSA " + L"Level 3 PPI ID assignment: %d.", + SpeOverflowInterrupt, + ARM_PPI_ID_PMBIRQ + ); + } +} + +/** + An ACPI_PARSER array describing the GICC Interrupt Controller Structure. +**/ +STATIC CONST ACPI_PARSER GicCParser[] = { + {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL}, + {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL}, + + {L"CPU Interface Number", 4, 4, L"0x%x", NULL, NULL, NULL, NULL}, + {L"ACPI Processor UID", 4, 8, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Flags", 4, 12, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Parking Protocol Version", 4, 16, L"0x%x", NULL, NULL, NULL, NULL}, + + {L"Performance Interrupt GSIV", 4, 20, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Parked Address", 8, 24, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Physical Base Address", 8, 32, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"GICV", 8, 40, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"GICH", 8, 48, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"VGIC Maintenance interrupt", 4, 56, L"0x%x", NULL, NULL, NULL, NULL}, + {L"GICR Base Address", 8, 60, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"MPIDR", 8, 68, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Processor Power Efficiency Class", 1, 76, L"0x%x", NULL, NULL, NULL, + NULL}, + {L"Reserved", 1, 77, L"0x%x", NULL, NULL, NULL, NULL}, + {L"SPE overflow Interrupt", 2, 78, L"0x%x", NULL, NULL, + ValidateSpeOverflowInterrupt, NULL} +}; + +/** + An ACPI_PARSER array describing the GICD Interrupt Controller Structure. +**/ +STATIC CONST ACPI_PARSER GicDParser[] = { + {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL}, + {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL}, + + {L"GIC ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Physical Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"System Vector Base", 4, 16, L"0x%x", NULL, NULL, + ValidateGICDSystemVectorBase, NULL}, + {L"GIC Version", 1, 20, L"%d", NULL, NULL, NULL, NULL}, + {L"Reserved", 3, 21, L"%x %x %x", Dump3Chars, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the MSI Frame Interrupt Controller Structure. +**/ +STATIC CONST ACPI_PARSER GicMSIFrameParser[] = { + {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL}, + {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL}, + + {L"MSI Frame ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Physical Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Flags", 4, 16, L"0x%x", NULL, NULL, NULL, NULL}, + + {L"SPI Count", 2, 20, L"%d", NULL, NULL, NULL, NULL}, + {L"SPI Base", 2, 22, L"0x%x", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the GICR Interrupt Controller Structure. +**/ +STATIC CONST ACPI_PARSER GicRParser[] = { + {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL}, + {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL}, + + {L"Discovery Range Base Address", 8, 4, L"0x%lx", NULL, NULL, NULL, + NULL}, + {L"Discovery Range Length", 4, 12, L"0x%x", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the GIC ITS Interrupt Controller Structure. +**/ +STATIC CONST ACPI_PARSER GicITSParser[] = { + {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL}, + {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL}, + + {L"GIC ITS ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Physical Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Reserved", 4, 16, L"0x%x", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the ACPI MADT Table. +**/ +STATIC CONST ACPI_PARSER MadtParser[] = { + PARSE_ACPI_HEADER (&AcpiHdrInfo), + {L"Local Interrupt Controller Address", 4, 36, L"0x%x", NULL, NULL, NULL, + NULL}, + {L"Flags", 4, 40, L"0x%x", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the MADT Interrupt Controller Structure Header Structure. +**/ +STATIC CONST ACPI_PARSER MadtInterruptControllerHeaderParser[] = { + {NULL, 1, 0, NULL, NULL, (VOID**)&MadtInterruptControllerType, NULL, NULL}, + {L"Length", 1, 1, NULL, NULL, (VOID**)&MadtInterruptControllerLength, NULL, + NULL}, + {L"Reserved", 2, 2, NULL, NULL, NULL, NULL, NULL} +}; + +/** + This function parses the ACPI MADT table. + When trace is enabled this function parses the MADT table and + traces the ACPI table fields. + + This function currently parses the following Interrupt Controller + Structures: + - GICC + - GICD + - GIC MSI Frame + - GICR + - GIC ITS + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiMadt ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ) +{ + UINT32 Offset; + UINT8* InterruptContollerPtr; + UINT32 GICDCount; + + GICDCount = 0; + + if (!Trace) { + return; + } + + Offset = ParseAcpi ( + TRUE, + 0, + "MADT", + Ptr, + AcpiTableLength, + PARSER_PARAMS (MadtParser) + ); + InterruptContollerPtr = Ptr + Offset; + + while (Offset < AcpiTableLength) { + // Parse Interrupt Controller Structure to obtain Length. + ParseAcpi ( + FALSE, + 0, + NULL, + InterruptContollerPtr, + AcpiTableLength - Offset, + PARSER_PARAMS (MadtInterruptControllerHeaderParser) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if ((MadtInterruptControllerType == NULL) || + (MadtInterruptControllerLength == NULL)) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient remaining table buffer length to read the " \ + L"Interrupt Controller Structure header. Length = %d.\n", + AcpiTableLength - Offset + ); + return; + } + + // Validate Interrupt Controller Structure length + if ((*MadtInterruptControllerLength == 0) || + ((Offset + (*MadtInterruptControllerLength)) > AcpiTableLength)) { + IncrementErrorCount (); + Print ( + L"ERROR: Invalid Interrupt Controller Structure length. " \ + L"Length = %d. Offset = %d. AcpiTableLength = %d.\n", + *MadtInterruptControllerLength, + Offset, + AcpiTableLength + ); + return; + } + + switch (*MadtInterruptControllerType) { + case EFI_ACPI_6_3_GIC: { + ParseAcpi ( + TRUE, + 2, + "GICC", + InterruptContollerPtr, + *MadtInterruptControllerLength, + PARSER_PARAMS (GicCParser) + ); + break; + } + + case EFI_ACPI_6_3_GICD: { + if (++GICDCount > 1) { + IncrementErrorCount (); + Print ( + L"ERROR: Only one GICD must be present," + L" GICDCount = %d\n", + GICDCount + ); + } + ParseAcpi ( + TRUE, + 2, + "GICD", + InterruptContollerPtr, + *MadtInterruptControllerLength, + PARSER_PARAMS (GicDParser) + ); + break; + } + + case EFI_ACPI_6_3_GIC_MSI_FRAME: { + ParseAcpi ( + TRUE, + 2, + "GIC MSI Frame", + InterruptContollerPtr, + *MadtInterruptControllerLength, + PARSER_PARAMS (GicMSIFrameParser) + ); + break; + } + + case EFI_ACPI_6_3_GICR: { + ParseAcpi ( + TRUE, + 2, + "GICR", + InterruptContollerPtr, + *MadtInterruptControllerLength, + PARSER_PARAMS (GicRParser) + ); + break; + } + + case EFI_ACPI_6_3_GIC_ITS: { + ParseAcpi ( + TRUE, + 2, + "GIC ITS", + InterruptContollerPtr, + *MadtInterruptControllerLength, + PARSER_PARAMS (GicITSParser) + ); + break; + } + + default: { + IncrementErrorCount (); + Print ( + L"ERROR: Unknown Interrupt Controller Structure," + L" Type = %d, Length = %d\n", + *MadtInterruptControllerType, + *MadtInterruptControllerLength + ); + } + } // switch + + InterruptContollerPtr += *MadtInterruptControllerLength; + Offset += *MadtInterruptControllerLength; + } // while +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Madt/MadtParser.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Madt/MadtParser.h new file mode 100644 index 00000000..c861f7a0 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Madt/MadtParser.h @@ -0,0 +1,40 @@ +/** @file + Header file for MADT table parser + + Copyright (c) 2019, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - Arm Generic Interrupt Controller Architecture Specification, + GIC architecture version 3 and version 4, issue E + - Arm Server Base System Architecture 5.0 +**/ + +#ifndef MADT_PARSER_H_ +#define MADT_PARSER_H_ + +/// +/// Level 3 base server system Private Peripheral Inerrupt (PPI) ID assignments +/// +#define ARM_PPI_ID_OVERFLOW_INTERRUPT_FROM_CNTP 30 +#define ARM_PPI_ID_OVERFLOW_INTERRUPT_FROM_CNTPS 29 +#define ARM_PPI_ID_OVERFLOW_INTERRUPT_FROM_CNTHV 28 +#define ARM_PPI_ID_OVERFLOW_INTERRUPT_FROM_CNTV 27 +#define ARM_PPI_ID_OVERFLOW_INTERRUPT_FROM_CNTHP 26 +#define ARM_PPI_ID_GIC_MAINTENANCE_INTERRUPT 25 +#define ARM_PPI_ID_CTIIRQ 24 +#define ARM_PPI_ID_PERFORMANCE_MONITORS_INTERRUPT 23 +#define ARM_PPI_ID_COMMIRQ 22 +#define ARM_PPI_ID_PMBIRQ 21 +#define ARM_PPI_ID_CNTHPS 20 +#define ARM_PPI_ID_CNTHVS 19 + +/// +/// PPI ID allowed ranges +/// +#define ARM_PPI_ID_MAX 31 +#define ARM_PPI_ID_MIN 16 +#define ARM_PPI_ID_EXTENDED_MAX 1119 +#define ARM_PPI_ID_EXTENDED_MIN 1056 + +#endif // MADT_PARSER_H_ diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Mcfg/McfgParser.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Mcfg/McfgParser.c new file mode 100644 index 00000000..4551e1d3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Mcfg/McfgParser.c @@ -0,0 +1,90 @@ +/** @file + MCFG table parser + + Copyright (c) 2016 - 2018, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - PCI Firmware Specification - Revision 3.2, January 26, 2015. +**/ + +#include +#include +#include "AcpiParser.h" +#include "AcpiTableParser.h" + +// Local variables +STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo; + +/** + An ACPI_PARSER array describing the ACPI MCFG Table. +**/ +STATIC CONST ACPI_PARSER McfgParser[] = { + PARSE_ACPI_HEADER (&AcpiHdrInfo), + {L"Reserved", 8, 36, L"0x%lx", NULL, NULL, NULL, NULL}, +}; + +/** + An ACPI_PARSER array describing the PCI configuration Space Base Address structure. +**/ +STATIC CONST ACPI_PARSER PciCfgSpaceBaseAddrParser[] = { + {L"Base Address", 8, 0, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"PCI Segment Group No.", 2, 8, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Start Bus No.", 1, 10, L"0x%x", NULL, NULL, NULL, NULL}, + {L"End Bus No.", 1, 11, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 4, 12, L"0x%x", NULL, NULL, NULL, NULL} +}; + +/** + This function parses the ACPI MCFG table. + When trace is enabled this function parses the MCFG table and + traces the ACPI table fields. + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiMcfg ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ) +{ + UINT32 Offset; + UINT32 PciCfgOffset; + UINT8* PciCfgSpacePtr; + + if (!Trace) { + return; + } + + Offset = ParseAcpi ( + TRUE, + 0, + "MCFG", + Ptr, + AcpiTableLength, + PARSER_PARAMS (McfgParser) + ); + + PciCfgSpacePtr = Ptr + Offset; + + while (Offset < AcpiTableLength) { + PciCfgOffset = ParseAcpi ( + TRUE, + 2, + "PCI Configuration Space", + PciCfgSpacePtr, + (AcpiTableLength - Offset), + PARSER_PARAMS (PciCfgSpaceBaseAddrParser) + ); + PciCfgSpacePtr += PciCfgOffset; + Offset += PciCfgOffset; + } +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Pcct/PcctParser.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Pcct/PcctParser.c new file mode 100644 index 00000000..bf07a49e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Pcct/PcctParser.c @@ -0,0 +1,615 @@ +/** @file + PCCT table parser + + Copyright (c) 2020, Arm Limited. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - ACPI 6.3 Specification - January 2019 +**/ + +#include +#include +#include +#include "AcpiParser.h" +#include "AcpiView.h" +#include "AcpiViewConfig.h" +#include "PcctParser.h" + +// Local variables +STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo; + +STATIC UINT32* PccGlobalFlags; +STATIC UINT8* PccSubspaceLength; +STATIC UINT8* PccSubspaceType; +STATIC UINT8* ExtendedPccSubspaceInterruptFlags; + +/** + This function validates the length coded on 4 bytes of a shared memory range + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateRangeLength4 ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + if (*(UINT32*)Ptr < MIN_EXT_PCC_SUBSPACE_MEM_RANGE_LEN) { + IncrementErrorCount (); + Print ( + L"\nError: Shared memory range length is too short.\n" + L"Length is %u when it should be greater than or equal to %u", + *(UINT32*)Ptr, + MIN_EXT_PCC_SUBSPACE_MEM_RANGE_LEN + ); + } +} + +/** + This function validates the length coded on 8 bytes of a shared memory range + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateRangeLength8 ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + if (*(UINT64*)Ptr <= MIN_MEMORY_RANGE_LENGTH) { + IncrementErrorCount (); + Print ( + L"\nError: Shared memory range length is too short.\n" + L"Length is %u when it should be greater than %u", + *(UINT64*)Ptr, + MIN_MEMORY_RANGE_LENGTH + ); + } +} + +/** + This function validates address space for type 0 structure. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidatePccType0Gas ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + switch (*(UINT8*)Ptr) { +#if !(defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64)) + case EFI_ACPI_6_3_SYSTEM_IO: +#endif //if not (defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64)) + case EFI_ACPI_6_3_SYSTEM_MEMORY: + return; + default: + IncrementErrorCount (); + Print (L"\nError: Invalid address space"); + } +} + +/** + This function validates address space for structures of types other than 0. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidatePccGas ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + switch (*(UINT8*)Ptr) { +#if !(defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64)) + case EFI_ACPI_6_3_SYSTEM_IO: +#endif //if not (defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64)) + case EFI_ACPI_6_3_FUNCTIONAL_FIXED_HARDWARE: + case EFI_ACPI_6_3_SYSTEM_MEMORY: + return; + default: + IncrementErrorCount (); + Print (L"\nError: Invalid address space"); + } +} + +/** + This function validates doorbell address space for type 4 structure. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidatePccDoorbellGas ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + // For slave subspaces this field is optional, if not present the field + // should just contain zeros. + if (*PccSubspaceType == EFI_ACPI_6_3_PCCT_SUBSPACE_TYPE_4_EXTENDED_PCC) { + if (IsZeroBuffer ( + Ptr, + sizeof (EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE) + )) { + return; + } + } + + ValidatePccGas (Ptr, Context); +} + +/** + This function validates interrupt acknowledge address space for + type 4 structure. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidatePccIntAckGas ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + // If the subspace does not support interrupts or the interrupt is + // edge driven the register may be omitted. A value of 0x0 on all + // 12 bytes of the GAS structure indicates the register is not + // present. + if (((*PccGlobalFlags & EFI_ACPI_6_3_PCCT_FLAGS_PLATFORM_INTERRUPT) != + EFI_ACPI_6_3_PCCT_FLAGS_PLATFORM_INTERRUPT) || + ((*ExtendedPccSubspaceInterruptFlags & + EFI_ACPI_6_3_PCCT_SUBSPACE_PLATFORM_INTERRUPT_FLAGS_MODE) == + EFI_ACPI_6_3_PCCT_SUBSPACE_PLATFORM_INTERRUPT_FLAGS_MODE)) { + if (IsZeroBuffer ( + Ptr, + sizeof (EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE) + )) { + return; + } + } + + ValidatePccGas (Ptr, Context); +} + +/** + This function validates error status address space for type 4 structure. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidatePccErrStatusGas ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + // This field is ignored by the OSPM on slave channels. + if (*PccSubspaceType == EFI_ACPI_6_3_PCCT_SUBSPACE_TYPE_4_EXTENDED_PCC) { + return; + } + + ValidatePccGas (Ptr, Context); +} + +/** + This function validates platform interrupt flags for type 4 structure. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidatePlatInterrupt ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + // If a slave subspace is present in the PCCT, then the global Platform + // Interrupt flag must be set to 1. + if ((*PccSubspaceType == EFI_ACPI_6_3_PCCT_SUBSPACE_TYPE_4_EXTENDED_PCC) && + ((*PccGlobalFlags & EFI_ACPI_6_3_PCCT_FLAGS_PLATFORM_INTERRUPT) != + EFI_ACPI_6_3_PCCT_FLAGS_PLATFORM_INTERRUPT)) { + IncrementErrorCount (); + Print ( + L"\nError: Global Platform interrupt flag must be set to 1" \ + L" if a PCC type 4 structure is present in PCCT." + ); + } +} + +/** + An ACPI_PARSER array describing the ACPI PCCT Table. +*/ +STATIC CONST ACPI_PARSER PcctParser[] = { + PARSE_ACPI_HEADER (&AcpiHdrInfo), + {L"Flags", 4, 36, NULL, NULL, (VOID**)&PccGlobalFlags, NULL, NULL}, + {L"Reserved", 8, 40, NULL, NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the platform communications channel subspace + structure header. +*/ +STATIC CONST ACPI_PARSER PccSubspaceHeaderParser[] = { + PCC_SUBSPACE_HEADER () + // ... Type Specific Fields ... +}; + +/** + An ACPI_PARSER array describing the Generic Communications Subspace - Type 0 +*/ +STATIC CONST ACPI_PARSER PccSubspaceType0Parser[] = { + PCC_SUBSPACE_HEADER (), + {L"Reserved", 6, 2, L"%x %x %x %x %x %x", Dump6Chars, NULL, NULL, NULL}, + {L"Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Memory Range Length", 8, 16, L"0x%lx", NULL, NULL, ValidateRangeLength8, + NULL}, + {L"Doorbell Register", 12, 24, NULL, DumpGas, NULL, ValidatePccType0Gas, + NULL}, + {L"Doorbell Preserve", 8, 36, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Doorbell Write", 8, 44, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Nominal Latency", 4, 52, L"%u", NULL, NULL, NULL, NULL}, + {L"Maximum Periodic Access Rate", 4, 56, L"%u", NULL, NULL, NULL, NULL}, + {L"Minimum Request Turnaround Time", 2, 60, L"%u", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the HW-Reduced Communications Subspace + - Type 1 +*/ +STATIC CONST ACPI_PARSER PccSubspaceType1Parser[] = { + PCC_SUBSPACE_HEADER (), + {L"Platform Interrupt", 4, 2, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Platform Interrupt Flags", 1, 6, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 1, 7, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Memory Range Length", 8, 16, L"0x%lx", NULL, NULL, ValidateRangeLength8, + NULL}, + {L"Doorbell Register", 12, 24, NULL, DumpGas, NULL, + ValidatePccGas, NULL}, + {L"Doorbell Preserve", 8, 36, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Doorbell Write", 8, 44, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Nominal Latency", 4, 52, L"%u", NULL, NULL, NULL, NULL}, + {L"Maximum Periodic Access Rate", 4, 56, L"%u", NULL, NULL, NULL, NULL}, + {L"Minimum Request Turnaround Time", 2, 60, L"%u", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the HW-Reduced Communications Subspace + - Type 2 +*/ +STATIC CONST ACPI_PARSER PccSubspaceType2Parser[] = { + PCC_SUBSPACE_HEADER (), + {L"Platform Interrupt", 4, 2, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Platform Interrupt Flags", 1, 6, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 1, 7, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Memory Range Length", 8, 16, L"0x%lx", NULL, NULL, ValidateRangeLength8, + NULL}, + {L"Doorbell Register", 12, 24, NULL, DumpGas, NULL, + ValidatePccGas, NULL}, + {L"Doorbell Preserve", 8, 36, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Doorbell Write", 8, 44, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Nominal Latency", 4, 52, L"%u", NULL, NULL, NULL, NULL}, + {L"Maximum Periodic Access Rate", 4, 56, L"%u", NULL, NULL, NULL, NULL}, + {L"Minimum Request Turnaround Time", 2, 60, L"%u", NULL, NULL, NULL, NULL}, + {L"Platform Interrupt Ack Register", 12, 62, NULL, DumpGas, NULL, + ValidatePccGas, NULL}, + {L"Platform Interrupt Ack Preserve", 8, 74, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Platform Interrupt Ack Write", 8, 82, L"0x%lx", NULL, NULL, + NULL, NULL}, +}; + +/** + An ACPI_PARSER array describing the Extended PCC Subspaces - Type 3/4 +*/ +STATIC CONST ACPI_PARSER PccSubspaceType3Parser[] = { + PCC_SUBSPACE_HEADER (), + {L"Platform Interrupt", 4, 2, L"0x%x", NULL, NULL, + ValidatePlatInterrupt, NULL}, + {L"Platform Interrupt Flags", 1, 6, L"0x%x", NULL, + (VOID**)&ExtendedPccSubspaceInterruptFlags, NULL, NULL}, + {L"Reserved", 1, 7, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Memory Range Length", 4, 16, L"0x%x", NULL, NULL, ValidateRangeLength4, + NULL}, + {L"Doorbell Register", 12, 20, NULL, DumpGas, NULL, + ValidatePccDoorbellGas, NULL}, + {L"Doorbell Preserve", 8, 32, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Doorbell Write", 8, 40, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Nominal Latency", 4, 48, L"%u", NULL, NULL, NULL, NULL}, + {L"Maximum Periodic Access Rate", 4, 52, L"%u", NULL, NULL, NULL, NULL}, + {L"Minimum Request Turnaround Time", 4, 56, L"%u", NULL, NULL, NULL, NULL}, + {L"Platform Interrupt Ack Register", 12, 60, NULL, DumpGas, NULL, + ValidatePccIntAckGas, NULL}, + {L"Platform Interrupt Ack Preserve", 8, 72, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Platform Interrupt Ack Set", 8, 80, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Reserved", 8, 88, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Cmd Complete Check Reg Addr", 12, 96, NULL, DumpGas, NULL, + ValidatePccGas, NULL}, + {L"Cmd Complete Check Mask", 8, 108, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Cmd Update Reg Addr", 12, 116, NULL, DumpGas, NULL, + ValidatePccGas, NULL}, + {L"Cmd Update Preserve mask", 8, 128, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Cmd Update Set mask", 8, 136, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Error Status Register", 12, 144, NULL, DumpGas, NULL, + ValidatePccErrStatusGas, NULL}, + {L"Error Status Mask", 8, 156, L"0x%lx", NULL, NULL, NULL, NULL}, +}; + +/** + This function parses the PCC Subspace type 0. + + @param [in] Ptr Pointer to the start of Subspace Structure. + @param [in] Length Length of the Subspace Structure. +**/ +STATIC +VOID +DumpPccSubspaceType0 ( + IN UINT8* Ptr, + IN UINT8 Length + ) +{ + ParseAcpi ( + TRUE, + 2, + "Subspace Type 0", + Ptr, + Length, + PARSER_PARAMS (PccSubspaceType0Parser) + ); +} + +/** + This function parses the PCC Subspace type 1. + + @param [in] Ptr Pointer to the start of the Subspace Structure. + @param [in] Length Length of the Subspace Structure. +**/ +STATIC +VOID +DumpPccSubspaceType1 ( + IN UINT8* Ptr, + IN UINT8 Length + ) +{ + ParseAcpi ( + TRUE, + 2, + "Subspace Type 1", + Ptr, + Length, + PARSER_PARAMS (PccSubspaceType1Parser) + ); +} + +/** + This function parses the PCC Subspace type 2. + + @param [in] Ptr Pointer to the start of the Subspace Structure. + @param [in] Length Length of the Subspace Structure. +**/ +STATIC +VOID +DumpPccSubspaceType2 ( + IN UINT8* Ptr, + IN UINT8 Length + ) +{ + ParseAcpi ( + TRUE, + 2, + "Subspace Type 2", + Ptr, + Length, + PARSER_PARAMS (PccSubspaceType2Parser) + ); +} + +/** + This function parses the PCC Subspace type 3. + + @param [in] Ptr Pointer to the start of the Subspace Structure. + @param [in] Length Length of the Subspace Structure. +**/ +STATIC +VOID +DumpPccSubspaceType3 ( + IN UINT8* Ptr, + IN UINT8 Length + ) +{ + ParseAcpi ( + TRUE, + 2, + "Subspace Type 3", + Ptr, + Length, + PARSER_PARAMS (PccSubspaceType3Parser) + ); +} + +/** + This function parses the PCC Subspace type 4. + + @param [in] Ptr Pointer to the start of the Subspace Structure. + @param [in] Length Length of the Subspace Structure. +**/ +STATIC +VOID +DumpPccSubspaceType4 ( + IN UINT8* Ptr, + IN UINT8 Length + ) +{ + ParseAcpi ( + TRUE, + 2, + "Subspace Type 4", + Ptr, + Length, + PARSER_PARAMS (PccSubspaceType3Parser) + ); +} + +/** + This function parses the ACPI PCCT table including its sub-structures + of type 0 through 4. + When trace is enabled this function parses the PCCT table and + traces the ACPI table fields. + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiPcct ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ) +{ + UINT32 Offset; + UINT8* PccSubspacePtr; + UINTN SubspaceCount; + + if (!Trace) { + return; + } + + Offset = ParseAcpi ( + TRUE, + 0, + "PCCT", + Ptr, + AcpiTableLength, + PARSER_PARAMS (PcctParser) + ); + + PccSubspacePtr = Ptr + Offset; + + SubspaceCount = 0; + while (Offset < AcpiTableLength) { + // Parse common structure header to obtain Type and Length. + ParseAcpi ( + FALSE, + 0, + NULL, + PccSubspacePtr, + AcpiTableLength - Offset, + PARSER_PARAMS (PccSubspaceHeaderParser) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if ((PccSubspaceType == NULL) || + (PccSubspaceLength == NULL)) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient remaining table buffer length to read the " \ + L"structure header. Length = %u.\n", + AcpiTableLength - Offset + ); + return; + } + + // Validate Structure length + if ((*PccSubspaceLength == 0) || + ((Offset + (*PccSubspaceLength)) > AcpiTableLength)) { + IncrementErrorCount (); + Print ( + L"ERROR: Invalid Structure length. " \ + L"Length = %u. Offset = %u. AcpiTableLength = %u.\n", + *PccSubspaceLength, + Offset, + AcpiTableLength + ); + return; + } + + switch (*PccSubspaceType) { + case EFI_ACPI_6_3_PCCT_SUBSPACE_TYPE_GENERIC: + DumpPccSubspaceType0 ( + PccSubspacePtr, + *PccSubspaceLength + ); + break; + case EFI_ACPI_6_3_PCCT_SUBSPACE_TYPE_1_HW_REDUCED_COMMUNICATIONS: + DumpPccSubspaceType1 ( + PccSubspacePtr, + *PccSubspaceLength + ); + break; + case EFI_ACPI_6_3_PCCT_SUBSPACE_TYPE_2_HW_REDUCED_COMMUNICATIONS: + DumpPccSubspaceType2 ( + PccSubspacePtr, + *PccSubspaceLength + ); + break; + case EFI_ACPI_6_3_PCCT_SUBSPACE_TYPE_3_EXTENDED_PCC: + DumpPccSubspaceType3 ( + PccSubspacePtr, + *PccSubspaceLength + ); + break; + case EFI_ACPI_6_3_PCCT_SUBSPACE_TYPE_4_EXTENDED_PCC: + DumpPccSubspaceType4 ( + PccSubspacePtr, + *PccSubspaceLength + ); + break; + default: + IncrementErrorCount (); + Print ( + L"ERROR: Unknown PCC subspace structure:" + L" Type = %u, Length = %u\n", + PccSubspaceType, + *PccSubspaceLength + ); + } + + PccSubspacePtr += *PccSubspaceLength; + Offset += *PccSubspaceLength; + SubspaceCount++; + } // while + + if (SubspaceCount > MAX_PCC_SUBSPACES) { + IncrementErrorCount (); + Print (L"ERROR: Too many PCC subspaces."); + } +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Pcct/PcctParser.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Pcct/PcctParser.h new file mode 100644 index 00000000..c8e84c36 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Pcct/PcctParser.h @@ -0,0 +1,33 @@ +/** @file + Header file for PCCT parser + + Copyright (c) 2020, Arm Limited. + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef PCCT_PARSER_H_ +#define PCCT_PARSER_H_ + +/** + Minimum value for the 'length' field in subspaces of types 0, 1 and 2. +*/ +#define MIN_MEMORY_RANGE_LENGTH 8 + +/** + Minimum value for the 'length' field in subspaces of types 3 and 4. +*/ +#define MIN_EXT_PCC_SUBSPACE_MEM_RANGE_LEN 16 + +/** + Maximum number of PCC subspaces. +*/ +#define MAX_PCC_SUBSPACES 256 + +/** + Parser for the header of any type of PCC subspace. +*/ +#define PCC_SUBSPACE_HEADER() \ + {L"Type", 1, 0, L"0x%x", NULL, (VOID**)&PccSubspaceType, NULL, NULL}, \ + {L"Length", 1, 1, L"%u", NULL, (VOID**)&PccSubspaceLength, NULL, NULL} + +#endif // PCCT_PARSER_H_ diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Pptt/PpttParser.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Pptt/PpttParser.c new file mode 100644 index 00000000..261fdee9 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Pptt/PpttParser.c @@ -0,0 +1,478 @@ +/** @file + PPTT table parser + + Copyright (c) 2019 - 2020, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - ACPI 6.3 Specification - January 2019 + - ARM Architecture Reference Manual ARMv8 (D.a) +**/ + +#include +#include +#include "AcpiParser.h" +#include "AcpiView.h" +#include "AcpiViewConfig.h" +#include "PpttParser.h" + +// Local variables +STATIC CONST UINT8* ProcessorTopologyStructureType; +STATIC CONST UINT8* ProcessorTopologyStructureLength; +STATIC CONST UINT32* NumberOfPrivateResources; +STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo; + +/** + This function validates the Cache Type Structure (Type 1) 'Number of sets' + field. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateCacheNumberOfSets ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + UINT32 NumberOfSets; + NumberOfSets = *(UINT32*)Ptr; + + if (NumberOfSets == 0) { + IncrementErrorCount (); + Print (L"\nERROR: Cache number of sets must be greater than 0"); + return; + } + +#if defined(MDE_CPU_ARM) || defined (MDE_CPU_AARCH64) + if (NumberOfSets > PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX) { + IncrementErrorCount (); + Print ( + L"\nERROR: When ARMv8.3-CCIDX is implemented the maximum cache number of " + L"sets must be less than or equal to %d", + PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX + ); + return; + } + + if (NumberOfSets > PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX) { + IncrementWarningCount (); + Print ( + L"\nWARNING: Without ARMv8.3-CCIDX, the maximum cache number of sets " + L"must be less than or equal to %d. Ignore this message if " + L"ARMv8.3-CCIDX is implemented", + PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX + ); + return; + } +#endif + +} + +/** + This function validates the Cache Type Structure (Type 1) 'Associativity' + field. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateCacheAssociativity ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + UINT8 Associativity; + Associativity = *(UINT8*)Ptr; + + if (Associativity == 0) { + IncrementErrorCount (); + Print (L"\nERROR: Cache associativity must be greater than 0"); + return; + } +} + +/** + This function validates the Cache Type Structure (Type 1) Line size field. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateCacheLineSize ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ +#if defined(MDE_CPU_ARM) || defined (MDE_CPU_AARCH64) + // Reference: ARM Architecture Reference Manual ARMv8 (D.a) + // Section D12.2.25: CCSIDR_EL1, Current Cache Size ID Register + // LineSize, bits [2:0] + // (Log2(Number of bytes in cache line)) - 4. + + UINT16 LineSize; + LineSize = *(UINT16*)Ptr; + + if ((LineSize < PPTT_ARM_CACHE_LINE_SIZE_MIN) || + (LineSize > PPTT_ARM_CACHE_LINE_SIZE_MAX)) { + IncrementErrorCount (); + Print ( + L"\nERROR: The cache line size must be between %d and %d bytes" + L" on ARM Platforms.", + PPTT_ARM_CACHE_LINE_SIZE_MIN, + PPTT_ARM_CACHE_LINE_SIZE_MAX + ); + return; + } + + if ((LineSize & (LineSize - 1)) != 0) { + IncrementErrorCount (); + Print (L"\nERROR: The cache line size is not a power of 2."); + } +#endif +} + +/** + This function validates the Cache Type Structure (Type 1) Attributes field. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateCacheAttributes ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + // Reference: Advanced Configuration and Power Interface (ACPI) Specification + // Version 6.2 Errata A, September 2017 + // Table 5-153: Cache Type Structure + UINT8 Attributes; + Attributes = *(UINT8*)Ptr; + + if ((Attributes & 0xE0) != 0) { + IncrementErrorCount (); + Print ( + L"\nERROR: Attributes bits [7:5] are reserved and must be zero.", + Attributes + ); + return; + } +} + +/** + An ACPI_PARSER array describing the ACPI PPTT Table. +**/ +STATIC CONST ACPI_PARSER PpttParser[] = { + PARSE_ACPI_HEADER (&AcpiHdrInfo) +}; + +/** + An ACPI_PARSER array describing the processor topology structure header. +**/ +STATIC CONST ACPI_PARSER ProcessorTopologyStructureHeaderParser[] = { + {L"Type", 1, 0, NULL, NULL, (VOID**)&ProcessorTopologyStructureType, + NULL, NULL}, + {L"Length", 1, 1, NULL, NULL, (VOID**)&ProcessorTopologyStructureLength, + NULL, NULL}, + {L"Reserved", 2, 2, NULL, NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the Processor Hierarchy Node Structure - Type 0. +**/ +STATIC CONST ACPI_PARSER ProcessorHierarchyNodeStructureParser[] = { + {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL}, + {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL}, + + {L"Flags", 4, 4, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Parent", 4, 8, L"0x%x", NULL, NULL, NULL, NULL}, + {L"ACPI Processor ID", 4, 12, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Number of private resources", 4, 16, L"%d", NULL, + (VOID**)&NumberOfPrivateResources, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the Cache Type Structure - Type 1. +**/ +STATIC CONST ACPI_PARSER CacheTypeStructureParser[] = { + {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL}, + {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL}, + + {L"Flags", 4, 4, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Next Level of Cache", 4, 8, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Size", 4, 12, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Number of sets", 4, 16, L"%d", NULL, NULL, ValidateCacheNumberOfSets, NULL}, + {L"Associativity", 1, 20, L"%d", NULL, NULL, ValidateCacheAssociativity, NULL}, + {L"Attributes", 1, 21, L"0x%x", NULL, NULL, ValidateCacheAttributes, NULL}, + {L"Line size", 2, 22, L"%d", NULL, NULL, ValidateCacheLineSize, NULL} +}; + +/** + An ACPI_PARSER array describing the ID Type Structure - Type 2. +**/ +STATIC CONST ACPI_PARSER IdStructureParser[] = { + {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL}, + {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL}, + + {L"VENDOR_ID", 4, 4, NULL, Dump4Chars, NULL, NULL, NULL}, + {L"LEVEL_1_ID", 8, 8, L"0x%x", NULL, NULL, NULL, NULL}, + {L"LEVEL_2_ID", 8, 16, L"0x%x", NULL, NULL, NULL, NULL}, + {L"MAJOR_REV", 2, 24, L"0x%x", NULL, NULL, NULL, NULL}, + {L"MINOR_REV", 2, 26, L"0x%x", NULL, NULL, NULL, NULL}, + {L"SPIN_REV", 2, 28, L"0x%x", NULL, NULL, NULL, NULL}, +}; + +/** + This function parses the Processor Hierarchy Node Structure (Type 0). + + @param [in] Ptr Pointer to the start of the Processor Hierarchy Node + Structure data. + @param [in] Length Length of the Processor Hierarchy Node Structure. +**/ +STATIC +VOID +DumpProcessorHierarchyNodeStructure ( + IN UINT8* Ptr, + IN UINT8 Length + ) +{ + UINT32 Offset; + UINT32 Index; + CHAR16 Buffer[OUTPUT_FIELD_COLUMN_WIDTH]; + + Offset = ParseAcpi ( + TRUE, + 2, + "Processor Hierarchy Node Structure", + Ptr, + Length, + PARSER_PARAMS (ProcessorHierarchyNodeStructureParser) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if (NumberOfPrivateResources == NULL) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient Processor Hierarchy Node length. Length = %d.\n", + Length + ); + return; + } + + // Make sure the Private Resource array lies inside this structure + if (Offset + (*NumberOfPrivateResources * sizeof (UINT32)) > Length) { + IncrementErrorCount (); + Print ( + L"ERROR: Invalid Number of Private Resources. " \ + L"PrivateResourceCount = %d. RemainingBufferLength = %d. " \ + L"Parsing of this structure aborted.\n", + *NumberOfPrivateResources, + Length - Offset + ); + return; + } + + Index = 0; + + // Parse the specified number of private resource references or the Processor + // Hierarchy Node length. Whichever is minimum. + while (Index < *NumberOfPrivateResources) { + UnicodeSPrint ( + Buffer, + sizeof (Buffer), + L"Private resources [%d]", + Index + ); + + PrintFieldName (4, Buffer); + Print ( + L"0x%x\n", + *((UINT32*)(Ptr + Offset)) + ); + + Offset += sizeof (UINT32); + Index++; + } +} + +/** + This function parses the Cache Type Structure (Type 1). + + @param [in] Ptr Pointer to the start of the Cache Type Structure data. + @param [in] Length Length of the Cache Type Structure. +**/ +STATIC +VOID +DumpCacheTypeStructure ( + IN UINT8* Ptr, + IN UINT8 Length + ) +{ + ParseAcpi ( + TRUE, + 2, + "Cache Type Structure", + Ptr, + Length, + PARSER_PARAMS (CacheTypeStructureParser) + ); +} + +/** + This function parses the ID Structure (Type 2). + + @param [in] Ptr Pointer to the start of the ID Structure data. + @param [in] Length Length of the ID Structure. +**/ +STATIC +VOID +DumpIDStructure ( + IN UINT8* Ptr, + IN UINT8 Length + ) +{ + ParseAcpi ( + TRUE, + 2, + "ID Structure", + Ptr, + Length, + PARSER_PARAMS (IdStructureParser) + ); +} + +/** + This function parses the ACPI PPTT table. + When trace is enabled this function parses the PPTT table and + traces the ACPI table fields. + + This function parses the following processor topology structures: + - Processor hierarchy node structure (Type 0) + - Cache Type Structure (Type 1) + - ID structure (Type 2) + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiPptt ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ) +{ + UINT32 Offset; + UINT8* ProcessorTopologyStructurePtr; + + if (!Trace) { + return; + } + + Offset = ParseAcpi ( + TRUE, + 0, + "PPTT", + Ptr, + AcpiTableLength, + PARSER_PARAMS (PpttParser) + ); + + ProcessorTopologyStructurePtr = Ptr + Offset; + + while (Offset < AcpiTableLength) { + // Parse Processor Hierarchy Node Structure to obtain Type and Length. + ParseAcpi ( + FALSE, + 0, + NULL, + ProcessorTopologyStructurePtr, + AcpiTableLength - Offset, + PARSER_PARAMS (ProcessorTopologyStructureHeaderParser) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if ((ProcessorTopologyStructureType == NULL) || + (ProcessorTopologyStructureLength == NULL)) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient remaining table buffer length to read the " \ + L"processor topology structure header. Length = %d.\n", + AcpiTableLength - Offset + ); + return; + } + + // Validate Processor Topology Structure length + if ((*ProcessorTopologyStructureLength == 0) || + ((Offset + (*ProcessorTopologyStructureLength)) > AcpiTableLength)) { + IncrementErrorCount (); + Print ( + L"ERROR: Invalid Processor Topology Structure length. " \ + L"Length = %d. Offset = %d. AcpiTableLength = %d.\n", + *ProcessorTopologyStructureLength, + Offset, + AcpiTableLength + ); + return; + } + + PrintFieldName (2, L"* Structure Offset *"); + Print (L"0x%x\n", Offset); + + switch (*ProcessorTopologyStructureType) { + case EFI_ACPI_6_2_PPTT_TYPE_PROCESSOR: + DumpProcessorHierarchyNodeStructure ( + ProcessorTopologyStructurePtr, + *ProcessorTopologyStructureLength + ); + break; + case EFI_ACPI_6_2_PPTT_TYPE_CACHE: + DumpCacheTypeStructure ( + ProcessorTopologyStructurePtr, + *ProcessorTopologyStructureLength + ); + break; + case EFI_ACPI_6_2_PPTT_TYPE_ID: + DumpIDStructure ( + ProcessorTopologyStructurePtr, + *ProcessorTopologyStructureLength + ); + break; + default: + IncrementErrorCount (); + Print ( + L"ERROR: Unknown processor topology structure:" + L" Type = %d, Length = %d\n", + *ProcessorTopologyStructureType, + *ProcessorTopologyStructureLength + ); + } + + ProcessorTopologyStructurePtr += *ProcessorTopologyStructureLength; + Offset += *ProcessorTopologyStructureLength; + } // while +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Pptt/PpttParser.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Pptt/PpttParser.h new file mode 100644 index 00000000..e84bd674 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Pptt/PpttParser.h @@ -0,0 +1,38 @@ +/** @file + Header file for PPTT parser + + Copyright (c) 2019, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - ARM Architecture Reference Manual ARMv8 (D.a) +**/ + +#ifndef PPTT_PARSER_H_ +#define PPTT_PARSER_H_ + +#if defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64) + +/// Cache parameters allowed by the architecture with +/// ARMv8.3-CCIDX (Cache extended number of sets) +/// Derived from CCSIDR_EL1 when ID_AA64MMFR2_EL1.CCIDX==0001 +#define PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX (1 << 24) +#define PPTT_ARM_CCIDX_CACHE_ASSOCIATIVITY_MAX (1 << 21) + +/// Cache parameters allowed by the architecture without +/// ARMv8.3-CCIDX (Cache extended number of sets) +/// Derived from CCSIDR_EL1 when ID_AA64MMFR2_EL1.CCIDX==0000 +#define PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX (1 << 15) +#define PPTT_ARM_CACHE_ASSOCIATIVITY_MAX (1 << 10) + +/// Common cache parameters +/// Derived from CCSIDR_EL1 +/// The LineSize is represented by bits 2:0 +/// (Log2(Number of bytes in cache line)) - 4 is used to represent +/// the LineSize bits. +#define PPTT_ARM_CACHE_LINE_SIZE_MAX (1 << 11) +#define PPTT_ARM_CACHE_LINE_SIZE_MIN (1 << 4) + +#endif // if defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64) + +#endif // PPTT_PARSER_H_ diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Rsdp/RsdpParser.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Rsdp/RsdpParser.c new file mode 100644 index 00000000..f0a16965 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Rsdp/RsdpParser.c @@ -0,0 +1,164 @@ +/** @file + RSDP table parser + + Copyright (c) 2016 - 2019, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - ACPI 6.2 Specification - Errata A, September 2017 +**/ + +#include +#include "AcpiParser.h" +#include "AcpiTableParser.h" + +// Local Variables +STATIC CONST UINT64* XsdtAddress; + +/** + This function validates the RSDT Address. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateRsdtAddress ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ +#if defined(MDE_CPU_ARM) || defined (MDE_CPU_AARCH64) + // Reference: Server Base Boot Requirements System Software on ARM Platforms + // Section: 4.2.1.1 RSDP + // Root System Description Pointer (RSDP), ACPI ? 5.2.5. + // - Within the RSDP, the RsdtAddress field must be null (zero) and the + // XsdtAddresss MUST be a valid, non-null, 64-bit value. + UINT32 RsdtAddr; + + RsdtAddr = *(UINT32*)Ptr; + + if (RsdtAddr != 0) { + IncrementErrorCount (); + Print ( + L"\nERROR: Rsdt Address = 0x%p. This must be NULL on ARM Platforms.", + RsdtAddr + ); + } +#endif +} + +/** + This function validates the XSDT Address. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateXsdtAddress ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ +#if defined(MDE_CPU_ARM) || defined (MDE_CPU_AARCH64) + // Reference: Server Base Boot Requirements System Software on ARM Platforms + // Section: 4.2.1.1 RSDP + // Root System Description Pointer (RSDP), ACPI ? 5.2.5. + // - Within the RSDP, the RsdtAddress field must be null (zero) and the + // XsdtAddresss MUST be a valid, non-null, 64-bit value. + UINT64 XsdtAddr; + + XsdtAddr = *(UINT64*)Ptr; + + if (XsdtAddr == 0) { + IncrementErrorCount (); + Print ( + L"\nERROR: Xsdt Address = 0x%p. This must not be NULL on ARM Platforms.", + XsdtAddr + ); + } +#endif +} + +/** + An array describing the ACPI RSDP Table. +**/ +STATIC CONST ACPI_PARSER RsdpParser[] = { + {L"Signature", 8, 0, NULL, Dump8Chars, NULL, NULL, NULL}, + {L"Checksum", 1, 8, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Oem ID", 6, 9, NULL, Dump6Chars, NULL, NULL, NULL}, + {L"Revision", 1, 15, L"%d", NULL, NULL, NULL, NULL}, + {L"RSDT Address", 4, 16, L"0x%x", NULL, NULL, ValidateRsdtAddress, NULL}, + {L"Length", 4, 20, L"%d", NULL, NULL, NULL, NULL}, + {L"XSDT Address", 8, 24, L"0x%lx", NULL, (VOID**)&XsdtAddress, + ValidateXsdtAddress, NULL}, + {L"Extended Checksum", 1, 32, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 3, 33, L"%x %x %x", Dump3Chars, NULL, NULL, NULL} +}; + +/** + This function parses the ACPI RSDP table. + + This function invokes the parser for the XSDT table. + * Note - This function does not support parsing of RSDT table. + + This function also performs a RAW dump of the ACPI table and + validates the checksum. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiRsdp ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ) +{ + if (Trace) { + DumpRaw (Ptr, AcpiTableLength); + VerifyChecksum (TRUE, Ptr, AcpiTableLength); + } + + ParseAcpi ( + Trace, + 0, + "RSDP", + Ptr, + AcpiTableLength, + PARSER_PARAMS (RsdpParser) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if (XsdtAddress == NULL) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient table length. AcpiTableLength = %d." \ + L"RSDP parsing aborted.\n", + AcpiTableLength + ); + return; + } + + // This code currently supports parsing of XSDT table only + // and does not parse the RSDT table. Platforms provide the + // RSDT to enable compatibility with ACPI 1.0 operating systems. + // Therefore the RSDT should not be used on ARM platforms. + if ((*XsdtAddress) == 0) { + IncrementErrorCount (); + Print (L"ERROR: XSDT Pointer is not set. RSDP parsing aborted.\n"); + return; + } + + ProcessAcpiTable ((UINT8*)(UINTN)(*XsdtAddress)); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Slit/SlitParser.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Slit/SlitParser.c new file mode 100644 index 00000000..3c9cb65b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Slit/SlitParser.c @@ -0,0 +1,188 @@ +/** @file + SLIT table parser + + Copyright (c) 2016 - 2019, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - ACPI 6.2 Specification - Errata A, September 2017 +**/ + +#include +#include +#include +#include "AcpiParser.h" +#include "AcpiTableParser.h" + +// Local Variables +STATIC CONST UINT64* SlitSystemLocalityCount; +STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo; + +/** + An ACPI_PARSER array describing the ACPI SLIT table. +**/ +STATIC CONST ACPI_PARSER SlitParser[] = { + PARSE_ACPI_HEADER (&AcpiHdrInfo), + {L"Number of System Localities", 8, 36, L"0x%lx", NULL, + (VOID**)&SlitSystemLocalityCount, NULL, NULL} +}; + +/** + Macro to get the value of a System Locality +**/ +#define SLIT_ELEMENT(Ptr, i, j) *(Ptr + (i * LocalityCount) + j) + +/** + This function parses the ACPI SLIT table. + When trace is enabled this function parses the SLIT table and + traces the ACPI table fields. + + This function also validates System Localities for the following: + - Diagonal elements have a normalized value of 10 + - Relative distance from System Locality at i*N+j is same as + j*N+i + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiSlit ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ) +{ + UINT32 Offset; + UINT32 Count; + UINT32 Index; + UINT32 LocalityCount; + UINT8* LocalityPtr; + CHAR16 Buffer[80]; // Used for AsciiName param of ParseAcpi + + if (!Trace) { + return; + } + + Offset = ParseAcpi ( + TRUE, + 0, + "SLIT", + Ptr, + AcpiTableLength, + PARSER_PARAMS (SlitParser) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if (SlitSystemLocalityCount == NULL) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient table length. AcpiTableLength = %d.\n", + AcpiTableLength + ); + return; + } + + /* + Despite the 'Number of System Localities' being a 64-bit field in SLIT, + the maximum number of localities that can be represented in SLIT is limited + by the 'Length' field of the ACPI table. + + Since the ACPI table length field is 32-bit wide. The maximum number of + localities that can be represented in SLIT can be calculated as: + + MaxLocality = sqrt (MAX_UINT32 - sizeof (EFI_ACPI_6_3_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_HEADER)) + = 65535 + = MAX_UINT16 + */ + if (*SlitSystemLocalityCount > MAX_UINT16) { + IncrementErrorCount (); + Print ( + L"ERROR: The Number of System Localities provided can't be represented " \ + L"in the SLIT table. SlitSystemLocalityCount = %ld. " \ + L"MaxLocalityCountAllowed = %d.\n", + *SlitSystemLocalityCount, + MAX_UINT16 + ); + return; + } + + LocalityCount = (UINT32)*SlitSystemLocalityCount; + + // Make sure system localities fit in the table buffer provided + if (Offset + (LocalityCount * LocalityCount) > AcpiTableLength) { + IncrementErrorCount (); + Print ( + L"ERROR: Invalid Number of System Localities. " \ + L"SlitSystemLocalityCount = %ld. AcpiTableLength = %d.\n", + *SlitSystemLocalityCount, + AcpiTableLength + ); + return; + } + + LocalityPtr = Ptr + Offset; + + // We only print the Localities if the count is less than 16 + // If the locality count is more than 16 then refer to the + // raw data dump. + if (LocalityCount < 16) { + UnicodeSPrint ( + Buffer, + sizeof (Buffer), + L"Entry[0x%lx][0x%lx]", + LocalityCount, + LocalityCount + ); + PrintFieldName (0, Buffer); + Print (L"\n"); + Print (L" "); + for (Index = 0; Index < LocalityCount; Index++) { + Print (L" (%3d) ", Index); + } + Print (L"\n"); + for (Count = 0; Count< LocalityCount; Count++) { + Print (L" (%3d) ", Count); + for (Index = 0; Index < LocalityCount; Index++) { + Print (L" %3d ", SLIT_ELEMENT (LocalityPtr, Count, Index)); + } + Print (L"\n"); + } + } + + // Validate + for (Count = 0; Count < LocalityCount; Count++) { + for (Index = 0; Index < LocalityCount; Index++) { + // Element[x][x] must be equal to 10 + if ((Count == Index) && (SLIT_ELEMENT (LocalityPtr, Count,Index) != 10)) { + IncrementErrorCount (); + Print ( + L"ERROR: Diagonal Element[0x%lx][0x%lx] (%3d)." + L" Normalized Value is not 10\n", + Count, + Index, + SLIT_ELEMENT (LocalityPtr, Count, Index) + ); + } + // Element[i][j] must be equal to Element[j][i] + if (SLIT_ELEMENT (LocalityPtr, Count, Index) != + SLIT_ELEMENT (LocalityPtr, Index, Count)) { + IncrementErrorCount (); + Print ( + L"ERROR: Relative distances for Element[0x%lx][0x%lx] (%3d) and \n" + L"Element[0x%lx][0x%lx] (%3d) do not match.\n", + Count, + Index, + SLIT_ELEMENT (LocalityPtr, Count, Index), + Index, + Count, + SLIT_ELEMENT (LocalityPtr, Index, Count) + ); + } + } + } +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Spcr/SpcrParser.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Spcr/SpcrParser.c new file mode 100644 index 00000000..34843b17 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Spcr/SpcrParser.c @@ -0,0 +1,144 @@ +/** @file + SPCR table parser + + Copyright (c) 2016 - 2019, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - Microsoft Serial Port Console Redirection Table + Specification - Version 1.03 - August 10, 2015. +**/ + +#include +#include +#include +#include "AcpiParser.h" +#include "AcpiTableParser.h" + +// Local variables +STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo; + +/** + This function validates the Interrupt Type. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateInterruptType ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ +#if defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64) + UINT8 InterruptType; + + InterruptType = *Ptr; + + if (InterruptType != + EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERRUPT_TYPE_GIC) { + IncrementErrorCount (); + Print ( + L"\nERROR: InterruptType = %d. This must be 8 on ARM Platforms", + InterruptType + ); + } +#endif +} + +/** + This function validates the Irq. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateIrq ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ +#if defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64) + UINT8 Irq; + + Irq = *Ptr; + + if (Irq != 0) { + IncrementErrorCount (); + Print ( + L"\nERROR: Irq = %d. This must be zero on ARM Platforms\n", + Irq + ); + } +#endif +} + +/** + An ACPI_PARSER array describing the ACPI SPCR Table. +**/ +STATIC CONST ACPI_PARSER SpcrParser[] = { + PARSE_ACPI_HEADER (&AcpiHdrInfo), + {L"Interface Type", 1, 36, L"%d", NULL, NULL, NULL, NULL}, + {L"Reserved", 3, 37, L"%x %x %x", Dump3Chars, NULL, NULL, NULL}, + {L"Base Address", 12, 40, NULL, DumpGas, NULL, NULL, NULL}, + {L"Interrupt Type", 1, 52, L"%d", NULL, NULL, ValidateInterruptType, NULL}, + {L"IRQ", 1, 53, L"%d", NULL, NULL, ValidateIrq, NULL}, + {L"Global System Interrupt", 4, 54, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Baud Rate", 1, 58, L"%d", NULL, NULL, NULL, NULL}, + {L"Parity", 1, 59, L"%d", NULL, NULL, NULL, NULL}, + {L"Stop Bits", 1, 60, L"%d", NULL, NULL, NULL, NULL}, + {L"Flow Control", 1, 61, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Terminal Type", 1, 62, L"%d", NULL, NULL, NULL, NULL}, + {L"Reserved", 1, 63, L"%x", NULL, NULL, NULL, NULL}, + + {L"PCI Device ID", 2, 64, L"0x%x", NULL, NULL, NULL, NULL}, + {L"PCI Vendor ID", 2, 66, L"0x%x", NULL, NULL, NULL, NULL}, + {L"PCI Bus Number", 1, 68, L"0x%x", NULL, NULL, NULL, NULL}, + {L"PCI Device Number", 1, 69, L"0x%x", NULL, NULL, NULL, NULL}, + {L"PCI Function Number", 1, 70, L"0x%x", NULL, NULL, NULL, NULL}, + {L"PCI Flags", 4, 71, L"0x%x", NULL, NULL, NULL, NULL}, + {L"PCI Segment", 1, 75, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 4, 76, L"%x", NULL, NULL, NULL, NULL} +}; + +/** + This function parses the ACPI SPCR table. + When trace is enabled this function parses the SPCR table and + traces the ACPI table fields. + + This function also performs validations of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiSpcr ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ) +{ + if (!Trace) { + return; + } + + // Dump the SPCR + ParseAcpi ( + TRUE, + 0, + "SPCR", + Ptr, + AcpiTableLength, + PARSER_PARAMS (SpcrParser) + ); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Srat/SratParser.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Srat/SratParser.c new file mode 100644 index 00000000..e41500ab --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Srat/SratParser.c @@ -0,0 +1,542 @@ +/** @file + SRAT table parser + + Copyright (c) 2016 - 2020, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - ACPI 6.3 Specification - January 2019 +**/ + +#include +#include +#include +#include "AcpiParser.h" +#include "AcpiTableParser.h" +#include "AcpiViewConfig.h" + +// Local Variables +STATIC CONST UINT8* SratRAType; +STATIC CONST UINT8* SratRALength; +STATIC CONST UINT8* SratDeviceHandleType; +STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo; + +/** + This function validates the Reserved field in the SRAT table header. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateSratReserved ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + if (*(UINT32*)Ptr != 1) { + IncrementErrorCount (); + Print (L"\nERROR: Reserved should be 1 for backward compatibility.\n"); + } +} + +/** + This function validates the Device Handle Type field in the Generic Initiator + Affinity Structure. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateSratDeviceHandleType ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + UINT8 DeviceHandleType; + + DeviceHandleType = *Ptr; + + if (DeviceHandleType > EFI_ACPI_6_3_PCI_DEVICE_HANDLE) { + IncrementErrorCount (); + Print ( + L"\nERROR: Invalid Device Handle Type: %d. Must be between 0 and %d.", + DeviceHandleType, + EFI_ACPI_6_3_PCI_DEVICE_HANDLE + ); + } +} + +/** + This function traces the PCI BDF Number field inside Device Handle - PCI + + @param [in] Format Format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +STATIC +VOID +EFIAPI +DumpSratPciBdfNumber ( + IN CONST CHAR16* Format, + IN UINT8* Ptr + ) +{ + CHAR16 Buffer[OUTPUT_FIELD_COLUMN_WIDTH]; + + Print (L"\n"); + + /* + The PCI BDF Number subfields are printed in the order specified in the ACPI + specification. The format of the 16-bit PCI BDF Number field is as follows: + + +-----+------+------+ + |DEV | FUNC | BUS | + +-----+------+------+ + |15:11| 10:8 | 7:0 | + +-----+------+------+ + */ + + // Print PCI Bus Number (Bits 7:0 of Byte 2) + UnicodeSPrint ( + Buffer, + sizeof (Buffer), + L"PCI Bus Number" + ); + PrintFieldName (4, Buffer); + Print ( + L"0x%x\n", + *Ptr + ); + + Ptr++; + + // Print PCI Device Number (Bits 7:3 of Byte 3) + UnicodeSPrint ( + Buffer, + sizeof (Buffer), + L"PCI Device Number" + ); + PrintFieldName (4, Buffer); + Print ( + L"0x%x\n", + (*Ptr & (BIT7 | BIT6 | BIT5 | BIT4 | BIT3)) >> 3 + ); + + // PCI Function Number (Bits 2:0 of Byte 3) + UnicodeSPrint ( + Buffer, + sizeof (Buffer), + L"PCI Function Number" + ); + PrintFieldName (4, Buffer); + Print ( + L"0x%x\n", + *Ptr & (BIT2 | BIT1 | BIT0) + ); +} + +/** + An ACPI_PARSER array describing the Device Handle - ACPI +**/ +STATIC CONST ACPI_PARSER SratDeviceHandleAcpiParser[] = { + {L"ACPI_HID", 8, 0, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"ACPI_UID", 4, 8, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 4, 12, L"0x%x", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the Device Handle - PCI +**/ +STATIC CONST ACPI_PARSER SratDeviceHandlePciParser[] = { + {L"PCI Segment", 2, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"PCI BDF Number", 2, 2, NULL, DumpSratPciBdfNumber, NULL, NULL, NULL}, + {L"Reserved", 12, 4, L"%x %x %x %x - %x %x %x %x - %x %x %x %x", Dump12Chars, + NULL, NULL, NULL} +}; + +/** + This function traces the Device Handle field inside Generic Initiator + Affinity Structure. + + @param [in] Format Format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +STATIC +VOID +EFIAPI +DumpSratDeviceHandle ( + IN CONST CHAR16* Format, + IN UINT8* Ptr + ) +{ + if (SratDeviceHandleType == NULL) { + IncrementErrorCount (); + Print (L"\nERROR: Device Handle Type read incorrectly.\n"); + return; + } + + Print (L"\n"); + + if (*SratDeviceHandleType == EFI_ACPI_6_3_ACPI_DEVICE_HANDLE) { + ParseAcpi ( + TRUE, + 2, + NULL, + Ptr, + sizeof (EFI_ACPI_6_3_DEVICE_HANDLE_ACPI), + PARSER_PARAMS (SratDeviceHandleAcpiParser) + ); + } else if (*SratDeviceHandleType == EFI_ACPI_6_3_PCI_DEVICE_HANDLE) { + ParseAcpi ( + TRUE, + 2, + NULL, + Ptr, + sizeof (EFI_ACPI_6_3_DEVICE_HANDLE_PCI), + PARSER_PARAMS (SratDeviceHandlePciParser) + ); + } +} + +/** + This function traces the APIC Proximity Domain field. + + @param [in] Format Format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +STATIC +VOID +EFIAPI +DumpSratApicProximity ( + IN CONST CHAR16* Format, + IN UINT8* Ptr + ) +{ + UINT32 ProximityDomain; + + ProximityDomain = Ptr[0] | (Ptr[1] << 8) | (Ptr[2] << 16); + + Print (Format, ProximityDomain); +} + +/** + An ACPI_PARSER array describing the SRAT Table. +**/ +STATIC CONST ACPI_PARSER SratParser[] = { + PARSE_ACPI_HEADER (&AcpiHdrInfo), + {L"Reserved", 4, 36, L"0x%x", NULL, NULL, ValidateSratReserved, NULL}, + {L"Reserved", 8, 40, L"0x%lx", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the Resource Allocation structure header. +**/ +STATIC CONST ACPI_PARSER SratResourceAllocationParser[] = { + {L"Type", 1, 0, NULL, NULL, (VOID**)&SratRAType, NULL, NULL}, + {L"Length", 1, 1, NULL, NULL, (VOID**)&SratRALength, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the GICC Affinity structure. +**/ +STATIC CONST ACPI_PARSER SratGicCAffinityParser[] = { + {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Length", 1, 1, L"0x%x", NULL, NULL, NULL, NULL}, + + {L"Proximity Domain", 4, 2, L"0x%x", NULL, NULL, NULL, NULL}, + {L"ACPI Processor UID", 4, 6, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Flags", 4, 10, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Clock Domain", 4, 14, L"0x%x", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the GIC ITS Affinity structure. +**/ +STATIC CONST ACPI_PARSER SratGicITSAffinityParser[] = { + {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Length", 1, 1, L"0x%x", NULL, NULL, NULL, NULL}, + + {L"Proximity Domain", 4, 2, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 2, 6, L"0x%x", NULL, NULL, NULL, NULL}, + {L"ITS Id", 4, 8, L"0x%x", NULL, NULL, NULL, NULL}, +}; + +/** + An ACPI_PARSER array describing the Generic Initiator Affinity Structure +**/ +STATIC CONST ACPI_PARSER SratGenericInitiatorAffinityParser[] = { + {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Length", 1, 1, L"0x%x", NULL, NULL, NULL, NULL}, + + {L"Reserved", 1, 2, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Device Handle Type", 1, 3, L"%d", NULL, (VOID**)&SratDeviceHandleType, + ValidateSratDeviceHandleType, NULL}, + {L"Proximity Domain", 4, 4, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Device Handle", 16, 8, L"%s", DumpSratDeviceHandle, NULL, NULL, NULL}, + {L"Flags", 4, 24, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 4, 28, L"0x%x", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the Memory Affinity structure. +**/ +STATIC CONST ACPI_PARSER SratMemAffinityParser[] = { + {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Length", 1, 1, L"0x%x", NULL, NULL, NULL, NULL}, + + {L"Proximity Domain", 4, 2, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 2, 6, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Base Address Low", 4, 8, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Base Address High", 4, 12, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Length Low", 4, 16, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Length High", 4, 20, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 4, 24, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Flags", 4, 28, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 8, 32, L"0x%lx", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the APIC/SAPIC Affinity structure. +**/ +STATIC CONST ACPI_PARSER SratApciSapicAffinityParser[] = { + {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Length", 1, 1, L"0x%x", NULL, NULL, NULL, NULL}, + + {L"Proximity Domain [7:0]", 1, 2, L"0x%x", NULL, NULL, NULL, NULL}, + {L"APIC ID", 1, 3, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Flags", 4, 4, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Local SAPIC EID", 1, 8, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Proximity Domain [31:8]", 3, 9, L"0x%x", DumpSratApicProximity, + NULL, NULL, NULL}, + {L"Clock Domain", 4, 12, L"0x%x", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the Processor Local x2APIC Affinity structure. +**/ +STATIC CONST ACPI_PARSER SratX2ApciAffinityParser[] = { + {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Length", 1, 1, L"0x%x", NULL, NULL, NULL, NULL}, + + {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Proximity Domain", 4, 4, L"0x%x", NULL, NULL, NULL, NULL}, + {L"X2APIC ID", 4, 8, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Flags", 4, 12, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Clock Domain", 4, 16, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 4, 20, L"0x%x", NULL, NULL, NULL, NULL} +}; + +/** + This function parses the ACPI SRAT table. + When trace is enabled this function parses the SRAT table and + traces the ACPI table fields. + + This function parses the following Resource Allocation Structures: + - Processor Local APIC/SAPIC Affinity Structure + - Memory Affinity Structure + - Processor Local x2APIC Affinity Structure + - GICC Affinity Structure + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiSrat ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ) +{ + UINT32 Offset; + UINT8* ResourcePtr; + UINT32 GicCAffinityIndex; + UINT32 GicITSAffinityIndex; + UINT32 GenericInitiatorAffinityIndex; + UINT32 MemoryAffinityIndex; + UINT32 ApicSapicAffinityIndex; + UINT32 X2ApicAffinityIndex; + CHAR8 Buffer[80]; // Used for AsciiName param of ParseAcpi + + GicCAffinityIndex = 0; + GicITSAffinityIndex = 0; + GenericInitiatorAffinityIndex = 0; + MemoryAffinityIndex = 0; + ApicSapicAffinityIndex = 0; + X2ApicAffinityIndex = 0; + + if (!Trace) { + return; + } + + Offset = ParseAcpi ( + TRUE, + 0, + "SRAT", + Ptr, + AcpiTableLength, + PARSER_PARAMS (SratParser) + ); + + ResourcePtr = Ptr + Offset; + + while (Offset < AcpiTableLength) { + ParseAcpi ( + FALSE, + 0, + NULL, + ResourcePtr, + AcpiTableLength - Offset, + PARSER_PARAMS (SratResourceAllocationParser) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if ((SratRAType == NULL) || + (SratRALength == NULL)) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient remaining table buffer length to read the " \ + L"Static Resource Allocation structure header. Length = %d.\n", + AcpiTableLength - Offset + ); + return; + } + + // Validate Static Resource Allocation Structure length + if ((*SratRALength == 0) || + ((Offset + (*SratRALength)) > AcpiTableLength)) { + IncrementErrorCount (); + Print ( + L"ERROR: Invalid Static Resource Allocation Structure length. " \ + L"Length = %d. Offset = %d. AcpiTableLength = %d.\n", + *SratRALength, + Offset, + AcpiTableLength + ); + return; + } + + switch (*SratRAType) { + case EFI_ACPI_6_3_GICC_AFFINITY: + AsciiSPrint ( + Buffer, + sizeof (Buffer), + "GICC Affinity Structure [%d]", + GicCAffinityIndex++ + ); + ParseAcpi ( + TRUE, + 2, + Buffer, + ResourcePtr, + *SratRALength, + PARSER_PARAMS (SratGicCAffinityParser) + ); + break; + + case EFI_ACPI_6_3_GIC_ITS_AFFINITY: + AsciiSPrint ( + Buffer, + sizeof (Buffer), + "GIC ITS Affinity Structure [%d]", + GicITSAffinityIndex++ + ); + ParseAcpi ( + TRUE, + 2, + Buffer, + ResourcePtr, + *SratRALength, + PARSER_PARAMS (SratGicITSAffinityParser) + ); + break; + + case EFI_ACPI_6_3_GENERIC_INITIATOR_AFFINITY: + AsciiSPrint ( + Buffer, + sizeof (Buffer), + "Generic Initiator Affinity Structure [%d]", + GenericInitiatorAffinityIndex++ + ); + ParseAcpi ( + TRUE, + 2, + Buffer, + ResourcePtr, + *SratRALength, + PARSER_PARAMS (SratGenericInitiatorAffinityParser) + ); + break; + + case EFI_ACPI_6_3_MEMORY_AFFINITY: + AsciiSPrint ( + Buffer, + sizeof (Buffer), + "Memory Affinity Structure [%d]", + MemoryAffinityIndex++ + ); + ParseAcpi ( + TRUE, + 2, + Buffer, + ResourcePtr, + *SratRALength, + PARSER_PARAMS (SratMemAffinityParser) + ); + break; + + case EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY: + AsciiSPrint ( + Buffer, + sizeof (Buffer), + "APIC/SAPIC Affinity Structure [%d]", + ApicSapicAffinityIndex++ + ); + ParseAcpi ( + TRUE, + 2, + Buffer, + ResourcePtr, + *SratRALength, + PARSER_PARAMS (SratApciSapicAffinityParser) + ); + break; + + case EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC_AFFINITY: + AsciiSPrint ( + Buffer, + sizeof (Buffer), + "X2APIC Affinity Structure [%d]", + X2ApicAffinityIndex++ + ); + ParseAcpi ( + TRUE, + 2, + Buffer, + ResourcePtr, + *SratRALength, + PARSER_PARAMS (SratX2ApciAffinityParser) + ); + break; + + default: + IncrementErrorCount (); + Print (L"ERROR: Unknown SRAT Affinity type = 0x%x\n", *SratRAType); + break; + } + + ResourcePtr += (*SratRALength); + Offset += (*SratRALength); + } +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Ssdt/SsdtParser.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Ssdt/SsdtParser.c new file mode 100644 index 00000000..7bf4c1fb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Ssdt/SsdtParser.c @@ -0,0 +1,42 @@ +/** @file + SSDT table parser + + Copyright (c) 2016 - 2018, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - ACPI 6.2 Specification - Errata A, September 2017 +**/ + +#include +#include +#include "AcpiParser.h" +#include "AcpiTableParser.h" + +/** + This function parses the ACPI SSDT table. + When trace is enabled this function parses the SSDT table and + traces the ACPI table fields. + For the SSDT table only the ACPI header fields are + parsed and traced. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiSsdt ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ) +{ + if (!Trace) { + return; + } + + DumpAcpiHeader (Ptr); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Xsdt/XsdtParser.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Xsdt/XsdtParser.c new file mode 100644 index 00000000..48f2bc8d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Xsdt/XsdtParser.c @@ -0,0 +1,140 @@ +/** @file + XSDT table parser + + Copyright (c) 2016 - 2019, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - ACPI 6.2 Specification - Errata A, September 2017 +**/ + +#include +#include +#include +#include "AcpiParser.h" +#include "AcpiTableParser.h" + +// Local variables +STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo; + +/** An ACPI_PARSER array describing the ACPI XSDT table. +*/ +STATIC CONST ACPI_PARSER XsdtParser[] = { + PARSE_ACPI_HEADER (&AcpiHdrInfo) +}; + +/** + Get the ACPI XSDT header info. +**/ +CONST ACPI_DESCRIPTION_HEADER_INFO * +EFIAPI +GetAcpiXsdtHeaderInfo ( + VOID +) +{ + return &AcpiHdrInfo; +} + +/** + This function parses the ACPI XSDT table and optionally traces the ACPI table fields. + + This function also performs validation of the XSDT table. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiXsdt ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ) +{ + UINT32 Offset; + UINT32 TableOffset; + UINT64* TablePointer; + UINTN EntryIndex; + CHAR16 Buffer[32]; + + Offset = ParseAcpi ( + Trace, + 0, + "XSDT", + Ptr, + AcpiTableLength, + PARSER_PARAMS (XsdtParser) + ); + + TableOffset = Offset; + + if (Trace) { + EntryIndex = 0; + TablePointer = (UINT64*)(Ptr + TableOffset); + while (Offset < AcpiTableLength) { + CONST UINT32* Signature; + CONST UINT32* Length; + CONST UINT8* Revision; + + if ((UINT64*)(UINTN)(*TablePointer) != NULL) { + UINT8* SignaturePtr; + + ParseAcpiHeader ( + (UINT8*)(UINTN)(*TablePointer), + &Signature, + &Length, + &Revision + ); + + SignaturePtr = (UINT8*)Signature; + + UnicodeSPrint ( + Buffer, + sizeof (Buffer), + L"Entry[%d] - %c%c%c%c", + EntryIndex++, + SignaturePtr[0], + SignaturePtr[1], + SignaturePtr[2], + SignaturePtr[3] + ); + } else { + UnicodeSPrint ( + Buffer, + sizeof (Buffer), + L"Entry[%d]", + EntryIndex++ + ); + } + + PrintFieldName (2, Buffer); + Print (L"0x%lx\n", *TablePointer); + + // Validate the table pointers are not NULL + if ((UINT64*)(UINTN)(*TablePointer) == NULL) { + IncrementErrorCount (); + Print ( + L"ERROR: Invalid table entry at 0x%lx, table address is 0x%lx\n", + TablePointer, + *TablePointer + ); + } + Offset += sizeof (UINT64); + TablePointer++; + } // while + } + + // Process the tables + Offset = TableOffset; + TablePointer = (UINT64*)(Ptr + TableOffset); + while (Offset < AcpiTableLength) { + if ((UINT64*)(UINTN)(*TablePointer) != NULL) { + ProcessAcpiTable ((UINT8*)(UINTN)(*TablePointer)); + } + Offset += sizeof (UINT64); + TablePointer++; + } // while +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.c new file mode 100644 index 00000000..a0b9def8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.c @@ -0,0 +1,447 @@ +/** @file + Main file for 'acpiview' Shell command function. + + Copyright (c) 2016 - 2020, Arm Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AcpiParser.h" +#include "AcpiTableParser.h" +#include "AcpiView.h" +#include "AcpiViewConfig.h" + +CONST CHAR16 gShellAcpiViewFileName[] = L"ShellCommand"; +EFI_HII_HANDLE gShellAcpiViewHiiHandle = NULL; + +/** + An array of acpiview command line parameters. +**/ +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-q", TypeFlag}, + {L"-d", TypeFlag}, + {L"-h", TypeFlag}, + {L"-l", TypeFlag}, + {L"-s", TypeValue}, + {L"-r", TypeValue}, + {NULL, TypeMax} +}; + +/** + A list of available table parsers. +*/ +STATIC +CONST +ACPI_TABLE_PARSER ParserList[] = { + {EFI_ACPI_6_3_ARM_ERROR_SOURCE_TABLE_SIGNATURE, ParseAcpiAest}, + {EFI_ACPI_6_2_BOOT_GRAPHICS_RESOURCE_TABLE_SIGNATURE, ParseAcpiBgrt}, + {EFI_ACPI_6_2_DEBUG_PORT_2_TABLE_SIGNATURE, ParseAcpiDbg2}, + {EFI_ACPI_6_2_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, + ParseAcpiDsdt}, + {EFI_ACPI_6_3_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE, ParseAcpiFacs}, + {EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE, ParseAcpiFadt}, + {EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE, ParseAcpiGtdt}, + {EFI_ACPI_6_3_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_SIGNATURE, ParseAcpiHmat}, + {EFI_ACPI_6_2_IO_REMAPPING_TABLE_SIGNATURE, ParseAcpiIort}, + {EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE, ParseAcpiMadt}, + {EFI_ACPI_6_2_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE, + ParseAcpiMcfg}, + {EFI_ACPI_6_2_PLATFORM_COMMUNICATIONS_CHANNEL_TABLE_SIGNATURE, + ParseAcpiPcct}, + {EFI_ACPI_6_2_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_STRUCTURE_SIGNATURE, + ParseAcpiPptt}, + {RSDP_TABLE_INFO, ParseAcpiRsdp}, + {EFI_ACPI_6_2_SYSTEM_LOCALITY_INFORMATION_TABLE_SIGNATURE, ParseAcpiSlit}, + {EFI_ACPI_6_2_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE, ParseAcpiSpcr}, + {EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_SIGNATURE, ParseAcpiSrat}, + {EFI_ACPI_6_2_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, ParseAcpiSsdt}, + {EFI_ACPI_6_2_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, ParseAcpiXsdt} +}; + +/** + This function registers all the available table parsers. + + @retval EFI_SUCCESS The parser is registered. + @retval EFI_ALREADY_STARTED The parser for the ACPI Table + was already registered. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_OUT_OF_RESOURCES No space to register the + parser. +**/ +EFI_STATUS +RegisterAllParsers ( + ) +{ + EFI_STATUS Status; + UINTN Count; + + Status = EFI_SUCCESS; + Count = sizeof (ParserList) / sizeof (ParserList[0]); + + while (Count-- != 0) { + Status = RegisterParser ( + ParserList[Count].Signature, + ParserList[Count].Parser + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + return Status; +} + +/** + Dump a buffer to a file. Print error message if a file cannot be created. + + @param[in] FileName The filename that shall be created to contain the buffer. + @param[in] Buffer Pointer to buffer that shall be dumped. + @param[in] BufferSize The size of buffer to be dumped in bytes. + + @return The number of bytes that were written +**/ +UINTN +EFIAPI +ShellDumpBufferToFile ( + IN CONST CHAR16* FileNameBuffer, + IN CONST VOID* Buffer, + IN CONST UINTN BufferSize + ) +{ + EFI_STATUS Status; + SHELL_FILE_HANDLE DumpFileHandle; + UINTN TransferBytes; + + Status = ShellOpenFileByName ( + FileNameBuffer, + &DumpFileHandle, + EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, + 0 + ); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_GEN_READONLY_MEDIA), + gShellAcpiViewHiiHandle, + L"acpiview" + ); + return 0; + } + + TransferBytes = BufferSize; + Status = ShellWriteFile ( + DumpFileHandle, + &TransferBytes, + (VOID *) Buffer + ); + + if (EFI_ERROR (Status)) { + Print (L"ERROR: Failed to write binary file.\n"); + TransferBytes = 0; + } else { + Print (L"DONE.\n"); + } + + ShellCloseFile (&DumpFileHandle); + return TransferBytes; +} + +/** + Return the file name of the help text file if not using HII. + + @return The string pointer to the file name. +**/ +CONST CHAR16* +EFIAPI +ShellCommandGetManFileNameAcpiView ( + VOID + ) +{ + return gShellAcpiViewFileName; +} + +/** + Function for 'acpiview' command. + + @param[in] ImageHandle Handle to the Image (NULL if internal). + @param[in] SystemTable Pointer to the System Table (NULL if internal). + + @retval SHELL_INVALID_PARAMETER The command line invocation could not be parsed + @retval SHELL_NOT_FOUND The command failed + @retval SHELL_SUCCESS The command was successful +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunAcpiView ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE* SystemTable + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + LIST_ENTRY* Package; + CHAR16* ProblemParam; + SHELL_FILE_HANDLE TmpDumpFileHandle; + CONST CHAR16* MandatoryTableSpecStr; + CONST CHAR16* SelectedTableName; + + // Set configuration defaults + AcpiConfigSetDefaults (); + + ShellStatus = SHELL_SUCCESS; + Package = NULL; + TmpDumpFileHandle = NULL; + + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR (Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_GEN_PROBLEM), + gShellAcpiViewHiiHandle, + L"acpiview", + ProblemParam + ); + FreePool (ProblemParam); + } else { + Print (L"acpiview: Error processing input parameter(s)\n"); + } + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + if (ShellCommandLineGetCount (Package) > 1) { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_GEN_TOO_MANY), + gShellAcpiViewHiiHandle, + L"acpiview" + ); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetFlag (Package, L"-?")) { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_GET_HELP_ACPIVIEW), + gShellAcpiViewHiiHandle, + L"acpiview" + ); + } else if (ShellCommandLineGetFlag (Package, L"-s") && + ShellCommandLineGetValue (Package, L"-s") == NULL) { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_GEN_NO_VALUE), + gShellAcpiViewHiiHandle, + L"acpiview", + L"-s" + ); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetFlag (Package, L"-r") && + ShellCommandLineGetValue (Package, L"-r") == NULL) { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_GEN_NO_VALUE), + gShellAcpiViewHiiHandle, + L"acpiview", + L"-r" + ); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if ((ShellCommandLineGetFlag (Package, L"-s") && + ShellCommandLineGetFlag (Package, L"-l"))) { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_GEN_TOO_MANY), + gShellAcpiViewHiiHandle, + L"acpiview" + ); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetFlag (Package, L"-d") && + !ShellCommandLineGetFlag (Package, L"-s")) { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_GEN_MISSING_OPTION), + gShellAcpiViewHiiHandle, + L"acpiview", + L"-s", + L"-d" + ); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // Turn on colour highlighting if requested + SetColourHighlighting (ShellCommandLineGetFlag (Package, L"-h")); + + // Surpress consistency checking if requested + SetConsistencyChecking (!ShellCommandLineGetFlag (Package, L"-q")); + + // Evaluate the parameters for mandatory ACPI table presence checks + SetMandatoryTableValidate (ShellCommandLineGetFlag (Package, L"-r")); + MandatoryTableSpecStr = ShellCommandLineGetValue (Package, L"-r"); + + if (MandatoryTableSpecStr != NULL) { + SetMandatoryTableSpec (ShellHexStrToUintn (MandatoryTableSpecStr)); + } + + if (ShellCommandLineGetFlag (Package, L"-l")) { + SetReportOption (ReportTableList); + } else { + SelectedTableName = ShellCommandLineGetValue (Package, L"-s"); + if (SelectedTableName != NULL) { + SelectAcpiTable (SelectedTableName); + SetReportOption (ReportSelected); + + if (ShellCommandLineGetFlag (Package, L"-d")) { + // Create a temporary file to check if the media is writable. + CHAR16 FileNameBuffer[MAX_FILE_NAME_LEN]; + SetReportOption (ReportDumpBinFile); + + UnicodeSPrint ( + FileNameBuffer, + sizeof (FileNameBuffer), + L".\\%s0000.tmp", + SelectedTableName + ); + + Status = ShellOpenFileByName ( + FileNameBuffer, + &TmpDumpFileHandle, + EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | + EFI_FILE_MODE_CREATE, + 0 + ); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_INVALID_PARAMETER; + TmpDumpFileHandle = NULL; + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_GEN_READONLY_MEDIA), + gShellAcpiViewHiiHandle, + L"acpiview" + ); + goto Done; + } + // Delete Temporary file. + ShellDeleteFile (&TmpDumpFileHandle); + } // -d + } // -s + } + + // Parse ACPI Table information + Status = AcpiView (SystemTable); + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_NOT_FOUND; + } + } + } + +Done: + if (Package != NULL) { + ShellCommandLineFreeVarList (Package); + } + return ShellStatus; +} + +/** + Constructor for the Shell AcpiView Command library. + + Install the handlers for acpiview UEFI Shell command. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. + + @retval EFI_SUCCESS The Shell command handlers were installed + successfully. + @retval EFI_DEVICE_ERROR Hii package failed to install. +**/ +EFI_STATUS +EFIAPI +UefiShellAcpiViewCommandLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + gShellAcpiViewHiiHandle = NULL; + + // Check Shell Profile Debug1 bit of the profiles mask + if ((PcdGet8 (PcdShellProfileMask) & BIT1) == 0) { + return EFI_SUCCESS; + } + + Status = RegisterAllParsers (); + if (EFI_ERROR (Status)) { + Print (L"acpiview: Error failed to register parser.\n"); + return Status; + } + + gShellAcpiViewHiiHandle = HiiAddPackages ( + &gShellAcpiViewHiiGuid, + gImageHandle, + UefiShellAcpiViewCommandLibStrings, + NULL + ); + if (gShellAcpiViewHiiHandle == NULL) { + return EFI_DEVICE_ERROR; + } + // Install our Shell command handler + ShellCommandRegisterCommandName ( + L"acpiview", + ShellCommandRunAcpiView, + ShellCommandGetManFileNameAcpiView, + 0, + L"acpiview", + TRUE, + gShellAcpiViewHiiHandle, + STRING_TOKEN (STR_GET_HELP_ACPIVIEW) + ); + + return EFI_SUCCESS; +} + +/** + Destructor for the library. free any resources. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. +**/ +EFI_STATUS +EFIAPI +UefiShellAcpiViewCommandLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + if (gShellAcpiViewHiiHandle != NULL) { + HiiRemovePackages (gShellAcpiViewHiiHandle); + } + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf new file mode 100644 index 00000000..377d0935 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf @@ -0,0 +1,85 @@ +## @file +# Provides Shell 'acpiview' command functions +# +# Copyright (c) 2016 - 2020, Arm Limited. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = UefiShellAcpiViewCommandLib + FILE_GUID = FB5B305E-84F5-461F-940D-82D345757AFA + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + LIBRARY_CLASS = AcpiViewCommandLib|UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = UefiShellAcpiViewCommandLibConstructor + DESTRUCTOR = UefiShellAcpiViewCommandLibDestructor + +[Sources.common] + AcpiParser.c + AcpiParser.h + AcpiTableParser.c + AcpiTableParser.h + AcpiView.c + AcpiView.h + AcpiViewConfig.c + AcpiViewConfig.h + Parsers/Aest/AestParser.c + Parsers/Bgrt/BgrtParser.c + Parsers/Dbg2/Dbg2Parser.c + Parsers/Dsdt/DsdtParser.c + Parsers/Facs/FacsParser.c + Parsers/Fadt/FadtParser.c + Parsers/Gtdt/GtdtParser.c + Parsers/Hmat/HmatParser.c + Parsers/Iort/IortParser.c + Parsers/Madt/MadtParser.c + Parsers/Madt/MadtParser.h + Parsers/Mcfg/McfgParser.c + Parsers/Pcct/PcctParser.c + Parsers/Pcct/PcctParser.h + Parsers/Pptt/PpttParser.c + Parsers/Pptt/PpttParser.h + Parsers/Rsdp/RsdpParser.c + Parsers/Slit/SlitParser.c + Parsers/Spcr/SpcrParser.c + Parsers/Srat/SratParser.c + Parsers/Ssdt/SsdtParser.c + Parsers/Xsdt/XsdtParser.c + UefiShellAcpiViewCommandLib.c + UefiShellAcpiViewCommandLib.uni + +[Sources.ARM, Sources.AARCH64] + Arm/SbbrValidator.h + Arm/SbbrValidator.c + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + FileHandleLib + HiiLib + MemoryAllocationLib + PcdLib + PrintLib + ShellCommandLib + ShellLib + UefiBootServicesTableLib + UefiLib + UefiRuntimeServicesTableLib + + +[FixedPcd] + gEfiShellPkgTokenSpaceGuid.PcdShellProfileMask ## CONSUMES + +[Guids] + gShellAcpiViewHiiGuid ## CONSUMES ## HII + gEfiAcpiTableGuid ## SOMETIMES_CONSUMES ## SystemTable diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.uni b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.uni new file mode 100644 index 00000000..393110e0 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.uni @@ -0,0 +1,139 @@ +// /** +// +// Copyright (c) 2016 - 2020, Arm Limited. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// Module Name: +// +// UefiShellAcpiViewCommandLib.uni +// +// Abstract: +// +// String definitions for UEFI Shell acpiview command +// +// +// */ + +/=# + +#langdef en-US "english" + +#string STR_GEN_PROBLEM #language en-US "%H%s%N: Unknown flag - '%H%s%N'\r\n" +#string STR_GEN_NO_VALUE #language en-US "%H%s%N: Missing argument for flag - '%H%s%N'\r\n" +#string STR_GEN_TOO_MANY #language en-US "%H%s%N: Too many arguments.\r\n" +#string STR_GEN_MISSING_OPTION #language en-US "%H%s%N: Missing option '%H%s%N' required by flag - '%H%s%N'\r\n" +#string STR_GEN_READONLY_MEDIA #language en-US "%H%s%N: Unable to write to the current directory, check if media is writable.\r\n" + +#string STR_GET_HELP_ACPIVIEW #language en-US "" +".TH acpiview 0 "Display ACPI information."\r\n" +".SH NAME\r\n" +"Display ACPI Table information.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"ACPIVIEW [[-?] | [[[[-l] | [-s AcpiTable [-d]]] [-q] [-h]] [-r Spec]]]\r\n" +" \r\n" +".SH OPTIONS\r\n" +" \r\n" +" -l - Display list of installed ACPI Tables.\r\n" +" -s - Display only the specified AcpiTable type and only support single\r\n" +" invocation option.\r\n" +" AcpiTable : The required ACPI Table type.\r\n" +" -d - Generate a binary file dump of the specified AcpiTable.\r\n" +" -q - Quiet. Suppress errors and warnings. Disables consistency checks.\r\n" +" -h - Enable colour highlighting.\r\n" +" -r - Validate that all required ACPI tables are installed\r\n" +" Spec : Specification to validate against.\r\n" +" For Arm, the possible values are:\r\n" +" 0 - Server Base Boot Requirements v1.0\r\n" +" 1 - Server Base Boot Requirements v1.1\r\n" +" 2 - Server Base Boot Requirements v1.2\r\n" +" -? - Show help.\r\n" +" \r\n" +".SH DESCRIPTION\r\n" +" \r\n" +" This program is provided to allow examination of ACPI table values from the\r\n" +" UEFI Shell. This can help with investigations, especially at that stage\r\n" +" where the tables are not enabling an OS to boot.\r\n" +" The program is not exhaustive, and only encapsulates detailed knowledge of a\r\n" +" limited number of table types.\r\n" +" \r\n" +" Default behaviour is to display the content of all tables installed.\r\n" +" 'Known' table types (listed in NOTES below) will be parsed and displayed\r\n" +" with descriptions and field values. Where appropriate a degree of\r\n" +" consistency checking is done and errors may be reported in the output.\r\n" +" Other table types will be displayed as an array of Hexadecimal bytes.\r\n" +" \r\n" +" To facilitate debugging, the -s and -d options can be used to generate a\r\n" +" binary file image of a table that can be copied elsewhere for investigation\r\n" +" using tools such as those provided by acpica.org. This is especially\r\n" +" relevant for AML type tables like DSDT and SSDT.\r\n" +" \r\n" +"NOTES:\r\n" +" 1. The AcpiTable parameter can match any installed table type.\r\n" +" Tables without specific handling will be displayed as a raw hex dump (or\r\n" +" dumped to a file if -d is used).\r\n" +" 2. -s option supports to display the specified AcpiTable type that is present\r\n" +" in the system. For normal type AcpiTable, it would display the data of the\r\n" +" AcpiTable and AcpiTable header. The following type may contain header type\r\n" +" other than AcpiTable header. The actual header can refer to the ACPI spec\r\n" +" 6.2\r\n" +" Extra A. Particular types:\r\n" +" AEST - Arm Error Source Table\r\n" +" APIC - Multiple APIC Description Table (MADT)\r\n" +" BGRT - Boot Graphics Resource Table\r\n" +" DBG2 - Debug Port Table 2\r\n" +" DSDT - Differentiated System Description Table\r\n" +" FACP - Fixed ACPI Description Table (FADT)\r\n" +" GTDT - Generic Timer Description Table\r\n" +" HMAT - Heterogeneous Memory Attributes Table\r\n" +" IORT - IO Remapping Table\r\n" +" MCFG - Memory Mapped Config Space Base Address Description Table\r\n" +" PPTT - Processor Properties Topology Table\r\n" +" RSDP - Root System Description Pointer\r\n" +" SLIT - System Locality Information Table\r\n" +" SPCR - Serial Port Console Redirection Table\r\n" +" SRAT - System Resource Affinity Table\r\n" +" SSDT - Secondary SystemDescription Table\r\n" +" XSDT - Extended System Description Table\r\n" +" \r\n" +".SH STANDARDS\r\n" +" \r\n" +" Table details correspond to those in 'Advanced Configuration and Power\r\n" +" Interface Specification' Version 6.2 Errata A, [September 2017]\r\n" +" (http://www.uefi.org/sites/default/files/resources/ACPI%206_2_A_Sept29.pdf)\r\n" +" \r\n" +" NOTE: The nature of the ACPI standard means that almost all tables in 6.1\r\n" +" will be 'backwards compatible' with prior version of the specification\r\n" +" in terms of structure, so formatted output should be correct. The main\r\n" +" exception will be that previously 'reserved' fields will be reported\r\n" +" with new names, where they have been added in later versions of the\r\n" +" specification.\r\n" +" \r\n" +".SH EXAMPLES\r\n" +" \r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display a list of the installed table types:\r\n" +" fs0:\> acpiview -l\r\n" +" \r\n" +" * To parse and display a specific table type:\r\n" +" fs0:\> acpiview -s GTDT\r\n" +" \r\n" +" * To save a binary dump of the contents of a table to a file\r\n" +" in the current working directory:\r\n" +" fs0:\> acpiview -s DSDT -d\r\n" +" \r\n" +" * To display contents of all ACPI tables:\r\n" +" fs0:\> acpiview\r\n" +" \r\n" +" * To check if all Server Base Boot Requirements (SBBR) v1.2 mandatory\r\n" +" ACPI tables are installed (Arm only):\r\n" +" fs0:\> acpiview -r 2\r\n" +" \r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS Data was displayed as requested.\r\n" +" SHELL_INVALID_PARAMETER ACPI Table parsing failed.\r\n" +" \r\n" + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.c new file mode 100644 index 00000000..a3b0224c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.c @@ -0,0 +1,1900 @@ +/** @file + Main file for BCFG command. + + (C) Copyright 2014-2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +STATIC CONST CHAR16 mFileName[] = L"ShellCommands"; +STATIC EFI_HII_HANDLE gShellBcfgHiiHandle = NULL; + +typedef enum { + BcfgTargetBootOrder = 0, + BcfgTargetDriverOrder = 1, + BcfgTargetMax = 2 +} BCFG_OPERATION_TARGET; + +typedef enum { + BcfgTypeDump = 0, + BcfgTypeAdd = 1, + BcfgTypeAddp = 2, + BcfgTypeAddh = 3, + BcfgTypeRm = 4, + BcfgTypeMv = 5, + BcfgTypeOpt = 6, + BcfgTypeMod = 7, + BcfgTypeModf = 8, + BcfgTypeModp = 9, + BcfgTypeModh = 10, + BcfgTypeMax = 11 +} BCFG_OPERATION_TYPE; + +typedef struct { + BCFG_OPERATION_TARGET Target; + BCFG_OPERATION_TYPE Type; + UINT16 Number1; + UINT16 Number2; + UINTN HandleIndex; + CHAR16 *FileName; + CHAR16 *Description; + UINT16 *Order; + CONST CHAR16 *OptData; +} BGFG_OPERATION; + +/** + Update the optional data for a boot or driver option. + + If optional data exists it will be changed. + + @param[in] Index The boot or driver option index update. + @param[in] DataSize The size in bytes of Data. + @param[in] Data The buffer for the optioanl data. + @param[in] Target The target of the operation. + + @retval EFI_SUCCESS The data was sucessfully updated. + @retval other A error occurred. +**/ +EFI_STATUS +UpdateOptionalData( + UINT16 Index, + UINTN DataSize, + UINT8 *Data, + IN CONST BCFG_OPERATION_TARGET Target + ) +{ + EFI_STATUS Status; + CHAR16 VariableName[12]; + UINTN OriginalSize; + UINT8 *OriginalData; + UINTN NewSize; + UINT8 *NewData; + UINTN OriginalOptionDataSize; + + UnicodeSPrint(VariableName, sizeof(VariableName), L"%s%04x", Target == BcfgTargetBootOrder?L"Boot":L"Driver", Index); + + OriginalSize = 0; + OriginalData = NULL; + NewData = NULL; + NewSize = 0; + + Status = gRT->GetVariable( + VariableName, + (EFI_GUID*)&gEfiGlobalVariableGuid, + NULL, + &OriginalSize, + OriginalData); + if (Status == EFI_BUFFER_TOO_SMALL) { + OriginalData = AllocateZeroPool(OriginalSize); + if (OriginalData == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + Status = gRT->GetVariable( + VariableName, + (EFI_GUID*)&gEfiGlobalVariableGuid, + NULL, + &OriginalSize, + OriginalData); + } + + if (!EFI_ERROR(Status)) { + // + // Allocate new struct and discard old optional data. + // + ASSERT (OriginalData != NULL); + OriginalOptionDataSize = sizeof(UINT32) + sizeof(UINT16) + StrSize(((CHAR16*)(OriginalData + sizeof(UINT32) + sizeof(UINT16)))); + OriginalOptionDataSize += (*(UINT16*)(OriginalData + sizeof(UINT32))); + OriginalOptionDataSize -= OriginalSize; + NewSize = OriginalSize - OriginalOptionDataSize + DataSize; + NewData = AllocatePool(NewSize); + if (NewData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + CopyMem (NewData, OriginalData, OriginalSize - OriginalOptionDataSize); + CopyMem(NewData + OriginalSize - OriginalOptionDataSize, Data, DataSize); + } + } + + if (!EFI_ERROR(Status)) { + // + // put the data back under the variable + // + Status = gRT->SetVariable( + VariableName, + (EFI_GUID*)&gEfiGlobalVariableGuid, + EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS, + NewSize, + NewData); + } + + SHELL_FREE_NON_NULL(OriginalData); + SHELL_FREE_NON_NULL(NewData); + return (Status); +} + +/** + This function will get a CRC for a boot option. + + @param[in, out] Crc The CRC value to return. + @param[in] BootIndex The boot option index to CRC. + + @retval EFI_SUCCESS The CRC was sucessfully returned. + @retval other A error occurred. +**/ +EFI_STATUS +GetBootOptionCrc( + UINT32 *Crc, + UINT16 BootIndex + ) +{ + CHAR16 VariableName[12]; + EFI_STATUS Status; + UINT8 *Buffer; + UINTN BufferSize; + + Buffer = NULL; + BufferSize = 0; + + // + // Get the data Buffer + // + UnicodeSPrint(VariableName, sizeof(VariableName), L"%Boot%04x", BootIndex); + Status = gRT->GetVariable( + VariableName, + (EFI_GUID*)&gEfiGlobalVariableGuid, + NULL, + &BufferSize, + NULL); + if (Status == EFI_BUFFER_TOO_SMALL) { + Buffer = AllocateZeroPool(BufferSize); + Status = gRT->GetVariable( + VariableName, + (EFI_GUID*)&gEfiGlobalVariableGuid, + NULL, + &BufferSize, + Buffer); + } + + // + // Get the CRC computed + // + if (!EFI_ERROR(Status)) { + Status = gBS->CalculateCrc32 (Buffer, BufferSize, Crc); + } + + SHELL_FREE_NON_NULL(Buffer); + return EFI_SUCCESS; +} + +/** + This function will populate the device path protocol parameter based on TheHandle. + + @param[in] TheHandle Driver handle. + @param[in, out] FilePath On a sucessful return the device path to the handle. + + @retval EFI_SUCCESS The device path was sucessfully returned. + @retval other A error from gBS->HandleProtocol. + + @sa HandleProtocol +**/ +EFI_STATUS +GetDevicePathForDriverHandle ( + IN EFI_HANDLE TheHandle, + IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath + ) +{ + EFI_STATUS Status; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath; + + Status = gBS->OpenProtocol ( + TheHandle, + &gEfiLoadedImageProtocolGuid, + (VOID**)&LoadedImage, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + Status = gBS->OpenProtocol ( + LoadedImage->DeviceHandle, + &gEfiDevicePathProtocolGuid, + (VOID**)&ImageDevicePath, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { +// *DevPath = DuplicateDevicePath (ImageDevicePath); +// *FilePath = DuplicateDevicePath (LoadedImage->FilePath); + *FilePath = AppendDevicePath(ImageDevicePath,LoadedImage->FilePath); + gBS->CloseProtocol( + LoadedImage->DeviceHandle, + &gEfiDevicePathProtocolGuid, + gImageHandle, + NULL); + } + gBS->CloseProtocol( + TheHandle, + &gEfiLoadedImageProtocolGuid, + gImageHandle, + NULL); + } + return (Status); +} + +/** + Functino to get Device Path by a handle. + + @param[in] TheHandle Use it to get DevicePath. + @param[in] Target Boot option target. + @param[in, out] DevicePath On a sucessful return the device path to the handle. + + @retval SHELL_INVALID_PARAMETER The handle was NULL. + @retval SHELL_NOT_FOUND Not found device path by handle. + @retval SHELL_SUCCESS Get device path successfully. +**/ +SHELL_STATUS +GetDevicePathByHandle( + IN EFI_HANDLE TheHandle, + IN BCFG_OPERATION_TARGET Target, + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + + UINTN DriverBindingHandleCount; + UINTN ParentControllerHandleCount; + UINTN ChildControllerHandleCount; + + ShellStatus = SHELL_SUCCESS; + + if (TheHandle == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"Handle Number"); + return SHELL_INVALID_PARAMETER; + } + + Status = PARSE_HANDLE_DATABASE_UEFI_DRIVERS (TheHandle, &DriverBindingHandleCount, NULL); + if (EFI_ERROR(Status)) { + DriverBindingHandleCount = 0; + } + + Status = PARSE_HANDLE_DATABASE_PARENTS (TheHandle, &ParentControllerHandleCount, NULL); + if (EFI_ERROR (Status)) { + ParentControllerHandleCount = 0; + } + + Status = ParseHandleDatabaseForChildControllers (TheHandle, &ChildControllerHandleCount, NULL); + if (EFI_ERROR (Status)) { + ChildControllerHandleCount = 0; + } + + Status = gBS->HandleProtocol (TheHandle, &gEfiDevicePathProtocolGuid, (VOID**)DevicePath); + + if ( DriverBindingHandleCount > 0 || + ParentControllerHandleCount > 0 || + ChildControllerHandleCount > 0 || + !EFI_ERROR(Status) + ) { + // + // The handle points to a real controller which has a device path. + // + if (Target == BcfgTargetDriverOrder) { + ShellPrintHiiEx ( + -1, + -1, + NULL,STRING_TOKEN (STR_GEN_PARAM_INV), + gShellBcfgHiiHandle, + L"bcfg", + L"Handle should point to driver image." + ); + ShellStatus = SHELL_NOT_FOUND; + } + } else { + // + // The handle points to a driver image. + // + if (Target == BcfgTargetBootOrder) { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_GEN_PARAM_INV), + gShellBcfgHiiHandle, + L"bcfg", + L"Handle should point to controller." + ); + ShellStatus = SHELL_NOT_FOUND; + } else { + if (EFI_ERROR (GetDevicePathForDriverHandle (TheHandle, DevicePath))) { + ShellStatus = SHELL_NOT_FOUND; + } + } + } + + return (ShellStatus); +} + +/** + Function to modify an option. + + @param[in] BcfgOperation Pointer to BCFG operation. + @param[in] OrderCount The number if items in CurrentOrder. + + @retval SHELL_SUCCESS The operation was successful. + @retval SHELL_INVALID_PARAMETER A parameter was invalid. + @retval SHELL_OUT_OF_RESOUCES A memory allocation failed. +**/ +SHELL_STATUS +BcfgMod ( + IN CONST BGFG_OPERATION *BcfgOperation, + IN CONST UINTN OrderCount + ) +{ + EFI_STATUS Status; + EFI_HANDLE CurHandle; + SHELL_STATUS ShellStatus; + CHAR16 OptionStr[40]; + EFI_SHELL_FILE_INFO *FileList; + EFI_SHELL_FILE_INFO *Arg; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *DevicePathBuffer; + EFI_DEVICE_PATH_PROTOCOL *DevicePathWalker; + EFI_BOOT_MANAGER_LOAD_OPTION LoadOption; + + ShellStatus = SHELL_SUCCESS; + FileList = NULL; + DevicePath = NULL; + DevicePathBuffer = NULL; + + ZeroMem (&LoadOption, sizeof(EFI_BOOT_MANAGER_LOAD_OPTION)); + + if ( (BcfgOperation->Type == BcfgTypeMod && BcfgOperation->Description == NULL) || + (BcfgOperation->Type == BcfgTypeModf && BcfgOperation->FileName == NULL) || + (BcfgOperation->Type == BcfgTypeModp && BcfgOperation->FileName == NULL) || + (BcfgOperation->Type == BcfgTypeModh && BcfgOperation->HandleIndex == 0) || + (BcfgOperation->Number1 > OrderCount) + ) { + return (SHELL_INVALID_PARAMETER); + } + + if (BcfgOperation->Type == BcfgTypeModh) { + CurHandle = ConvertHandleIndexToHandle (BcfgOperation->HandleIndex); + ShellStatus = GetDevicePathByHandle (CurHandle, BcfgOperation->Target, &DevicePathBuffer); + if (ShellStatus == SHELL_SUCCESS) { + DevicePath = DuplicateDevicePath (DevicePathBuffer); + } + } else if (BcfgOperation->Type == BcfgTypeModf || BcfgOperation->Type == BcfgTypeModp) { + // + // Get Device Path by FileName. + // + ShellOpenFileMetaArg ((CHAR16 *)BcfgOperation->FileName, EFI_FILE_MODE_READ, &FileList); + if (FileList == NULL) { + // + // The name of file matched nothing. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellBcfgHiiHandle, L"bcfg", BcfgOperation->FileName); + ShellStatus = SHELL_INVALID_PARAMETER; + } + else if (FileList->Link.ForwardLink != FileList->Link.BackLink) { + // + // If the name of file expanded to multiple names, it's fail. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_FILE), gShellBcfgHiiHandle, L"bcfg", BcfgOperation->FileName); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Arg = (EFI_SHELL_FILE_INFO *)GetFirstNode (&FileList->Link); + if (EFI_ERROR (Arg->Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_FILE_OPEN), gShellBcfgHiiHandle, L"bcfg", BcfgOperation->FileName); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + DevicePathBuffer = gEfiShellProtocol->GetDevicePathFromFilePath (Arg->FullName); + if (DevicePathBuffer == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_FILE_DP), gShellBcfgHiiHandle, L"bcfg", Arg->FullName); + ShellStatus = SHELL_UNSUPPORTED; + } + } + } + + if (ShellStatus == SHELL_SUCCESS) { + if (BcfgOperation->Type == BcfgTypeModp) { + ShellStatus = SHELL_INVALID_PARAMETER; + DevicePathWalker = DevicePathBuffer; + while (!IsDevicePathEnd (DevicePathWalker)) { + if ( DevicePathType (DevicePathWalker) == MEDIA_DEVICE_PATH && + DevicePathSubType (DevicePathWalker) == MEDIA_HARDDRIVE_DP + ) { + // + // We found the portion of device path starting with the hard driver partition. + // + ShellStatus = SHELL_SUCCESS; + DevicePath = DuplicateDevicePath (DevicePathWalker); + break; + } else { + DevicePathWalker = NextDevicePathNode (DevicePathWalker); + } + } + } else { + DevicePath = DuplicateDevicePath (DevicePathBuffer); + } + + FreePool (DevicePathBuffer); + } + } + + if (ShellStatus == SHELL_SUCCESS) { + if (BcfgOperation->Target == BcfgTargetBootOrder) { + UnicodeSPrint (OptionStr, sizeof (OptionStr), L"Boot%04x", BcfgOperation->Order[BcfgOperation->Number1]); + } else { + UnicodeSPrint (OptionStr, sizeof (OptionStr), L"Driver%04x", BcfgOperation->Order[BcfgOperation->Number1]); + } + Status = EfiBootManagerVariableToLoadOption (OptionStr, &LoadOption); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_NONE), gShellBcfgHiiHandle); + ShellStatus = SHELL_NOT_FOUND; + } + } + + if (ShellStatus == SHELL_SUCCESS) { + if (BcfgOperation->Type == BcfgTypeMod) { + SHELL_FREE_NON_NULL (LoadOption.Description); + LoadOption.Description = AllocateCopyPool (StrSize (BcfgOperation->Description), BcfgOperation->Description); + } else { + SHELL_FREE_NON_NULL (LoadOption.FilePath); + LoadOption.FilePath = DuplicateDevicePath (DevicePath); + } + + Status = EfiBootManagerLoadOptionToVariable (&LoadOption); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_SET_VAR_FAIL), gShellBcfgHiiHandle, L"bcfg", OptionStr); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } + + EfiBootManagerFreeLoadOption (&LoadOption); + + if (DevicePath != NULL) { + FreePool (DevicePath); + } + + if (FileList != NULL) { + ShellCloseFileMetaArg (&FileList); + } + + return (ShellStatus); +} + +/** + Function to add a option. + + @param[in] Position The position to add Target at. + @param[in] File The file to make the target. + @param[in] Desc The description text. + @param[in] CurrentOrder The pointer to the current order of items. + @param[in] OrderCount The number if items in CurrentOrder. + @param[in] Target The info on the option to add. + @param[in] UseHandle TRUE to use HandleNumber, FALSE to use File and Desc. + @param[in] UsePath TRUE to convert to devicepath. + @param[in] HandleNumber The handle number to add. + + @retval SHELL_SUCCESS The operation was successful. + @retval SHELL_INVALID_PARAMETER A parameter was invalid. +**/ +SHELL_STATUS +BcfgAdd( + IN UINTN Position, + IN CONST CHAR16 *File, + IN CONST CHAR16 *Desc, + IN CONST UINT16 *CurrentOrder, + IN CONST UINTN OrderCount, + IN CONST BCFG_OPERATION_TARGET Target, + IN CONST BOOLEAN UseHandle, + IN CONST BOOLEAN UsePath, + IN CONST UINTN HandleNumber + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *DevPath; + EFI_DEVICE_PATH_PROTOCOL *FilePath; + CHAR16 *Str; + UINT8 *TempByteBuffer; + UINT8 *TempByteStart; + EFI_SHELL_FILE_INFO *Arg; + EFI_SHELL_FILE_INFO *FileList; + CHAR16 OptionStr[40]; + UINTN DescSize, FilePathSize; + BOOLEAN Found; + UINTN TargetLocation; + UINTN Index; + EFI_HANDLE *Handles; + EFI_HANDLE CurHandle; + UINTN DriverBindingHandleCount; + UINTN ParentControllerHandleCount; + UINTN ChildControllerHandleCount; + SHELL_STATUS ShellStatus; + UINT16 *NewOrder; + + if (!UseHandle) { + if (File == NULL || Desc == NULL) { + return (SHELL_INVALID_PARAMETER); + } + } else { + if (HandleNumber == 0) { + return (SHELL_INVALID_PARAMETER); + } + } + + if (Position > OrderCount) { + Position = OrderCount; + } + + Str = NULL; + FilePath = NULL; + FileList = NULL; + Handles = NULL; + ShellStatus = SHELL_SUCCESS; + TargetLocation = 0xFFFF; + + if (UseHandle) { + CurHandle = ConvertHandleIndexToHandle(HandleNumber); + if (CurHandle == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"Handle Number"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + if (Target == BcfgTargetBootOrder) { + // + //Make sure that the handle should point to a real controller + // + Status = PARSE_HANDLE_DATABASE_UEFI_DRIVERS ( + CurHandle, + &DriverBindingHandleCount, + NULL); + + Status = PARSE_HANDLE_DATABASE_PARENTS ( + CurHandle, + &ParentControllerHandleCount, + NULL); + + Status = ParseHandleDatabaseForChildControllers ( + CurHandle, + &ChildControllerHandleCount, + NULL); + + if (DriverBindingHandleCount > 0 + || ParentControllerHandleCount > 0 + || ChildControllerHandleCount > 0) { + FilePath = NULL; + Status = gBS->HandleProtocol ( + CurHandle, + &gEfiDevicePathProtocolGuid, + (VOID**)&FilePath); + } + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_HANDLE), gShellBcfgHiiHandle, L"bcfg", HandleNumber); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } else { + // + //Make sure that the handle should point to driver, not a controller. + // + Status = PARSE_HANDLE_DATABASE_UEFI_DRIVERS ( + CurHandle, + &DriverBindingHandleCount, + NULL); + + Status = PARSE_HANDLE_DATABASE_PARENTS ( + CurHandle, + &ParentControllerHandleCount, + NULL); + + Status = ParseHandleDatabaseForChildControllers ( + CurHandle, + &ChildControllerHandleCount, + NULL); + + Status = gBS->HandleProtocol ( + CurHandle, + &gEfiDevicePathProtocolGuid, + (VOID**)&FilePath); + + if (DriverBindingHandleCount > 0 + || ParentControllerHandleCount > 0 + || ChildControllerHandleCount > 0 + || !EFI_ERROR(Status) ) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"Handle Number"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // Get the DevicePath from the loaded image information. + // + Status = GetDevicePathForDriverHandle(CurHandle, &FilePath); + } + } + } + } else { + // + // Get file info + // + ShellOpenFileMetaArg ((CHAR16*)File, EFI_FILE_MODE_READ, &FileList); + + if (FileList == NULL) { + // + // If filename matched nothing fail + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellBcfgHiiHandle, L"bcfg", File); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (FileList->Link.ForwardLink != FileList->Link.BackLink) { + // + // If filename expanded to multiple names, fail + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_FILE), gShellBcfgHiiHandle, L"bcfg", File); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Arg = (EFI_SHELL_FILE_INFO*)GetFirstNode(&FileList->Link); + if (EFI_ERROR(Arg->Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_FILE_OPEN), gShellBcfgHiiHandle, L"bcfg", File); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // Build FilePath to the filename + // + + // + // get the device path + // + DevicePath = gEfiShellProtocol->GetDevicePathFromFilePath(Arg->FullName); + if (DevicePath == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_FILE_DP), gShellBcfgHiiHandle, L"bcfg", Arg->FullName); + ShellStatus = SHELL_UNSUPPORTED; + } else { + if (UsePath) { + DevPath = DevicePath; + ShellStatus = SHELL_INVALID_PARAMETER; + while (!IsDevicePathEnd(DevPath)) { + if ((DevicePathType(DevPath) == MEDIA_DEVICE_PATH) && + (DevicePathSubType(DevPath) == MEDIA_HARDDRIVE_DP)) { + + // + // If we find it use it instead + // + ShellStatus = SHELL_SUCCESS; + FilePath = DuplicateDevicePath (DevPath); + break; + } + DevPath = NextDevicePathNode(DevPath); + } + } else { + FilePath = DuplicateDevicePath(DevicePath); + } + FreePool(DevicePath); + } + } + } + } + + + if (ShellStatus == SHELL_SUCCESS) { + // + // Find a free target ,a brute force implementation + // + Found = FALSE; + for (TargetLocation=0; TargetLocation < 0xFFFF; TargetLocation++) { + Found = TRUE; + for (Index=0; Index < OrderCount; Index++) { + if (CurrentOrder[Index] == TargetLocation) { + Found = FALSE; + break; + } + } + + if (Found) { + break; + } + } + + if (TargetLocation == 0xFFFF) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_TARGET_NF), gShellBcfgHiiHandle, L"bcfg"); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_TARGET), gShellBcfgHiiHandle, TargetLocation); + } + } + + if (ShellStatus == SHELL_SUCCESS) { + // + // Add the option + // + DescSize = StrSize(Desc); + FilePathSize = GetDevicePathSize (FilePath); + + TempByteBuffer = AllocateZeroPool(sizeof(UINT32) + sizeof(UINT16) + DescSize + FilePathSize); + if (TempByteBuffer != NULL) { + TempByteStart = TempByteBuffer; + *((UINT32 *) TempByteBuffer) = LOAD_OPTION_ACTIVE; // Attributes + TempByteBuffer += sizeof (UINT32); + + *((UINT16 *) TempByteBuffer) = (UINT16)FilePathSize; // FilePathListLength + TempByteBuffer += sizeof (UINT16); + + CopyMem (TempByteBuffer, Desc, DescSize); + TempByteBuffer += DescSize; + ASSERT (FilePath != NULL); + CopyMem (TempByteBuffer, FilePath, FilePathSize); + + UnicodeSPrint (OptionStr, sizeof(OptionStr), L"%s%04x", Target == BcfgTargetBootOrder?L"Boot":L"Driver", TargetLocation); + Status = gRT->SetVariable ( + OptionStr, + &gEfiGlobalVariableGuid, + EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS, + sizeof(UINT32) + sizeof(UINT16) + DescSize + FilePathSize, + TempByteStart + ); + + FreePool(TempByteStart); + } else { + Status = EFI_OUT_OF_RESOURCES; + } + + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_SET_VAR_FAIL), gShellBcfgHiiHandle, L"bcfg", OptionStr); + } else { + NewOrder = AllocateZeroPool ((OrderCount + 1) * sizeof (NewOrder[0])); + if (NewOrder != NULL) { + CopyMem (NewOrder, CurrentOrder, (OrderCount) * sizeof (NewOrder[0])); + + // + // Insert target into order list + // + for (Index = OrderCount; Index > Position; Index--) { + NewOrder[Index] = NewOrder[Index - 1]; + } + + NewOrder[Position] = (UINT16) TargetLocation; + Status = gRT->SetVariable ( + Target == BcfgTargetBootOrder ? L"BootOrder" : L"DriverOrder", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + (OrderCount + 1) * sizeof (UINT16), + NewOrder + ); + + FreePool (NewOrder); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_WRITE_FAIL), gShellBcfgHiiHandle, L"bcfg", Target == BcfgTargetBootOrder ? L"BootOrder" : L"DriverOrder"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Print (L"bcfg: Add %s as %x\n", OptionStr, Position); + } + } + } + } + +// +//If always Free FilePath, will free devicepath in system when use "addh" +// + if (FilePath!=NULL && !UseHandle) { + FreePool (FilePath); + } + + if (Str != NULL) { + FreePool(Str); + } + + if (Handles != NULL) { + FreePool (Handles); + } + + if (FileList != NULL) { + ShellCloseFileMetaArg (&FileList); + } + + return (ShellStatus); +} + +/** + Funciton to remove an item. + + @param[in] Target The target item to move. + @param[in] CurrentOrder The pointer to the current order of items. + @param[in] OrderCount The number if items in CurrentOrder. + @param[in] Location The current location of the Target. + + @retval SHELL_SUCCESS The operation was successful. + @retval SHELL_INVALID_PARAMETER A parameter was invalid. +**/ +SHELL_STATUS +BcfgRemove( + IN CONST BCFG_OPERATION_TARGET Target, + IN CONST UINT16 *CurrentOrder, + IN CONST UINTN OrderCount, + IN CONST UINT16 Location + ) +{ + CHAR16 VariableName[12]; + UINT16 *NewOrder; + EFI_STATUS Status; + UINTN NewCount; + + UnicodeSPrint(VariableName, sizeof(VariableName), L"%s%04x", Target == BcfgTargetBootOrder?L"Boot":L"Driver", CurrentOrder[Location]); + Status = gRT->SetVariable( + VariableName, + (EFI_GUID*)&gEfiGlobalVariableGuid, + EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS, + 0, + NULL); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_WRITE_FAIL), gShellBcfgHiiHandle, L"bcfg", VariableName); + return (SHELL_INVALID_PARAMETER); + } + NewOrder = AllocateZeroPool(OrderCount*sizeof(CurrentOrder[0])); + if (NewOrder != NULL) { + NewCount = OrderCount; + CopyMem(NewOrder, CurrentOrder, OrderCount*sizeof(CurrentOrder[0])); + CopyMem(NewOrder+Location, NewOrder+Location+1, (OrderCount - Location - 1)*sizeof(CurrentOrder[0])); + NewCount--; + + Status = gRT->SetVariable( + Target == BcfgTargetBootOrder?(CHAR16*)L"BootOrder":(CHAR16*)L"DriverOrder", + (EFI_GUID*)&gEfiGlobalVariableGuid, + EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS, + NewCount*sizeof(NewOrder[0]), + NewOrder); + FreePool(NewOrder); + } else { + Status = EFI_OUT_OF_RESOURCES; + } + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_WRITE_FAIL), gShellBcfgHiiHandle, L"bcfg", Target == BcfgTargetBootOrder?(CHAR16*)L"BootOrder":(CHAR16*)L"DriverOrder"); + return (SHELL_INVALID_PARAMETER); + } + return (SHELL_SUCCESS); +} + +/** + Funciton to move a item to another location. + + @param[in] Target The target item to move. + @param[in] CurrentOrder The pointer to the current order of items. + @param[in] OrderCount The number if items in CurrentOrder. + @param[in] OldLocation The current location of the Target. + @param[in] NewLocation The desired location of the Target. + + @retval SHELL_SUCCESS The operation was successful. + @retval SHELL_INVALID_PARAMETER A parameter was invalid. +**/ +SHELL_STATUS +BcfgMove( + IN CONST BCFG_OPERATION_TARGET Target, + IN CONST UINT16 *CurrentOrder, + IN CONST UINTN OrderCount, + IN CONST UINT16 OldLocation, + IN UINT16 NewLocation + ) +{ + UINT16 *NewOrder; + EFI_STATUS Status; + UINT16 Temp; + + NewOrder = AllocateCopyPool(OrderCount*sizeof(CurrentOrder[0]), CurrentOrder); + if (NewOrder == NULL) { + return (SHELL_OUT_OF_RESOURCES); + } + + // + // correct the new location + // + if (NewLocation >= OrderCount) { + if (OrderCount > 0) { + NewLocation = (UINT16)OrderCount - 1; + } else { + NewLocation = 0; + } + } + + Temp = CurrentOrder[OldLocation]; + CopyMem(NewOrder+OldLocation, NewOrder+OldLocation+1, (OrderCount - OldLocation - 1)*sizeof(CurrentOrder[0])); + CopyMem(NewOrder+NewLocation+1, NewOrder+NewLocation, (OrderCount - NewLocation - 1)*sizeof(CurrentOrder[0])); + NewOrder[NewLocation] = Temp; + + Status = gRT->SetVariable( + Target == BcfgTargetBootOrder?(CHAR16*)L"BootOrder":(CHAR16*)L"DriverOrder", + (EFI_GUID*)&gEfiGlobalVariableGuid, + EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS, + OrderCount*sizeof(CurrentOrder[0]), + NewOrder); + + FreePool(NewOrder); + + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_WRITE_FAIL), gShellBcfgHiiHandle, L"bcfg", Target == BcfgTargetBootOrder?(CHAR16*)L"BootOrder":(CHAR16*)L"DriverOrder"); + return (SHELL_INVALID_PARAMETER); + } + return (SHELL_SUCCESS); +} + +/** + Function to add optional data to an option. + + @param[in] OptData The optional data to add. + @param[in] CurrentOrder The pointer to the current order of items. + @param[in] OrderCount The number if items in CurrentOrder. + @param[in] Target The target of the operation. + + @retval SHELL_SUCCESS The operation was succesful. +**/ +SHELL_STATUS +BcfgAddOpt( + IN CONST CHAR16 *OptData, + IN CONST UINT16 *CurrentOrder, + IN CONST UINTN OrderCount, + IN CONST BCFG_OPERATION_TARGET Target + ) +{ + EFI_KEY_OPTION NewKeyOption; + EFI_KEY_OPTION *KeyOptionBuffer; + SHELL_STATUS ShellStatus; + EFI_STATUS Status; + UINT16 OptionIndex; + UINT16 LoopCounter; + UINT64 Intermediate; + CONST CHAR16 *Temp; + CONST CHAR16 *Walker; + CHAR16 *FileName; + CHAR16 *Temp2; + CHAR16 *Data; + UINT32 KeyIndex; + CHAR16 VariableName[12]; + VOID *VariableData; + + SHELL_FILE_HANDLE FileHandle; + + Status = EFI_SUCCESS; + ShellStatus = SHELL_SUCCESS; + Walker = OptData; + FileName = NULL; + Data = NULL; + KeyOptionBuffer = NULL; + VariableData = NULL; + + ZeroMem(&NewKeyOption, sizeof(EFI_KEY_OPTION)); + ZeroMem(VariableName, sizeof(VariableName)); + + while(Walker[0] == L' ') { + Walker++; + } + + // + // Get the index of the variable we are changing. + // + Status = ShellConvertStringToUint64(Walker, &Intermediate, TRUE, TRUE); + if (EFI_ERROR(Status) || (((UINT16)Intermediate) != Intermediate) || StrStr(Walker, L" ") == NULL || ((UINT16)Intermediate) > ((UINT16)OrderCount)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"Option Index"); + ShellStatus = SHELL_INVALID_PARAMETER; + return (ShellStatus); + } + OptionIndex = (UINT16)Intermediate; + + Temp = StrStr(Walker, L" "); + if (Temp != NULL) { + Walker = Temp; + } + while(Walker[0] == L' ') { + Walker++; + } + + // + // determine whether we have file with data, quote delimited information, or a hot-key + // + if (Walker[0] == L'\"') { + // + // quoted filename or quoted information. + // + Temp = StrStr(Walker+1, L"\""); + if (Temp == NULL || StrLen(Temp) != 1) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", Walker); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + FileName = StrnCatGrow(&FileName, NULL, Walker+1, 0); + if (FileName == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellBcfgHiiHandle, L"bcfg"); + ShellStatus = SHELL_OUT_OF_RESOURCES; + return (ShellStatus); + } + Temp2 = StrStr(FileName, L"\""); + ASSERT(Temp2 != NULL); + Temp2[0] = CHAR_NULL; + Temp2++; + if (StrLen(Temp2)>0) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", Walker); + ShellStatus = SHELL_INVALID_PARAMETER; + } + if (EFI_ERROR(ShellFileExists(Walker))) { + // + // Not a file. must be misc information. + // + Data = FileName; + FileName = NULL; + } else { + FileName = StrnCatGrow(&FileName, NULL, Walker, 0); + } + } + } else { + // + // filename or hot key information. + // + if (StrStr(Walker, L" ") == NULL) { + // + // filename + // + if (EFI_ERROR(ShellFileExists(Walker))) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FIND_FAIL), gShellBcfgHiiHandle, L"bcfg", Walker); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + FileName = StrnCatGrow(&FileName, NULL, Walker, 0); + } + } else { + if (Target != BcfgTargetBootOrder) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_BOOT_ONLY), gShellBcfgHiiHandle, L"bcfg"); + ShellStatus = SHELL_INVALID_PARAMETER; + } + + if (ShellStatus == SHELL_SUCCESS) { + // + // Get hot key information + // + Status = ShellConvertStringToUint64(Walker, &Intermediate, FALSE, TRUE); + if (EFI_ERROR(Status) || (((UINT32)Intermediate) != Intermediate) || StrStr(Walker, L" ") == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", Walker); + ShellStatus = SHELL_INVALID_PARAMETER; + } + NewKeyOption.KeyData.PackedValue = (UINT32)Intermediate; + Temp = StrStr(Walker, L" "); + if (Temp != NULL) { + Walker = Temp; + } + while(Walker[0] == L' ') { + Walker++; + } + } + + if (ShellStatus == SHELL_SUCCESS) { + // + // Now we know how many EFI_INPUT_KEY structs we need to attach to the end of the EFI_KEY_OPTION struct. + // Re-allocate with the added information. + // + KeyOptionBuffer = AllocatePool (sizeof(EFI_KEY_OPTION) + (sizeof(EFI_INPUT_KEY) * NewKeyOption.KeyData.Options.InputKeyCount)); + if (KeyOptionBuffer == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_MEM), gShellBcfgHiiHandle, L"bcfg"); + ShellStatus = SHELL_OUT_OF_RESOURCES; + return ShellStatus; + } + CopyMem (KeyOptionBuffer, &NewKeyOption, sizeof(EFI_KEY_OPTION)); + } + for (LoopCounter = 0 ; ShellStatus == SHELL_SUCCESS && LoopCounter < NewKeyOption.KeyData.Options.InputKeyCount; LoopCounter++) { + // + // ScanCode + // + Status = ShellConvertStringToUint64(Walker, &Intermediate, FALSE, TRUE); + if (EFI_ERROR(Status) || (((UINT16)Intermediate) != Intermediate) || StrStr(Walker, L" ") == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", Walker); + ShellStatus = SHELL_INVALID_PARAMETER; + } + ((EFI_INPUT_KEY*)(((UINT8*)KeyOptionBuffer) + sizeof(EFI_KEY_OPTION)))[LoopCounter].ScanCode = (UINT16)Intermediate; + Temp = StrStr(Walker, L" "); + if (Temp != NULL) { + Walker = Temp; + } + while(Walker[0] == L' ') { + Walker++; + } + + // + // UnicodeChar + // + Status = ShellConvertStringToUint64(Walker, &Intermediate, FALSE, TRUE); + if (EFI_ERROR(Status) || (((UINT16)Intermediate) != Intermediate)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", Walker); + ShellStatus = SHELL_INVALID_PARAMETER; + } + ((EFI_INPUT_KEY*)(((UINT8*)KeyOptionBuffer) + sizeof(EFI_KEY_OPTION)))[LoopCounter].UnicodeChar = (UINT16)Intermediate; + Temp = StrStr(Walker, L" "); + if (Temp != NULL) { + Walker = Temp; + } + while(Walker[0] == L' ') { + Walker++; + } + } + + if (ShellStatus == SHELL_SUCCESS) { + // + // Now do the BootOption / BootOptionCrc + // + ASSERT (OptionIndex <= OrderCount); + KeyOptionBuffer->BootOption = CurrentOrder[OptionIndex]; + Status = GetBootOptionCrc(&(KeyOptionBuffer->BootOptionCrc), KeyOptionBuffer->BootOption); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"Option Index"); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } + + if (ShellStatus == SHELL_SUCCESS) { + for (Temp2 = NULL, KeyIndex = 0 ; KeyIndex <= 0xFFFF ; KeyIndex++) { + UnicodeSPrint(VariableName, sizeof(VariableName), L"Key%04x", KeyIndex); + Status = GetEfiGlobalVariable2 (VariableName, &VariableData, NULL); + if (Status == EFI_NOT_FOUND) { + break; + } + if (!EFI_ERROR(Status)) { + SHELL_FREE_NON_NULL(VariableData); + } + } + if (KeyIndex <= 0xFFFF) { + Status = gRT->SetVariable( + VariableName, + (EFI_GUID*)&gEfiGlobalVariableGuid, + EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS, + sizeof(EFI_KEY_OPTION) + (sizeof(EFI_INPUT_KEY) * NewKeyOption.KeyData.Options.InputKeyCount), + KeyOptionBuffer); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_SET_VAR_FAIL), gShellBcfgHiiHandle, L"bcfg", VariableName); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_VAR_NO_NUM), gShellBcfgHiiHandle, L"bcfg"); + ShellStatus = SHELL_INVALID_PARAMETER; + } + ASSERT(FileName == NULL && Data == NULL); + } + } + } + + // + // Shouldn't be possible to have have both. Neither is ok though. + // + ASSERT(FileName == NULL || Data == NULL); + + if (ShellStatus == SHELL_SUCCESS && (FileName != NULL || Data != NULL)) { + if (FileName != NULL) { + // + // Open the file and populate the data buffer. + // + Status = ShellOpenFileByName( + FileName, + &FileHandle, + EFI_FILE_MODE_READ, + 0); + if (!EFI_ERROR(Status)) { + Status = ShellGetFileSize(FileHandle, &Intermediate); + } + Data = AllocateZeroPool((UINTN)Intermediate); + if (Data == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_MEM), gShellBcfgHiiHandle, L"bcfg"); + ShellStatus = SHELL_OUT_OF_RESOURCES; + } + if (!EFI_ERROR(Status)) { + Status = ShellReadFile(FileHandle, (UINTN *)&Intermediate, Data); + } + } else { + Intermediate = StrSize(Data); + } + + if (!EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS && Data != NULL) { + Status = UpdateOptionalData(CurrentOrder[OptionIndex], (UINTN)Intermediate, (UINT8*)Data, Target); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_SET_VAR_FAIL), gShellBcfgHiiHandle, L"bcfg", VariableName); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } + if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_SET_VAR_FAIL), gShellBcfgHiiHandle, L"bcfg", VariableName); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } + + SHELL_FREE_NON_NULL(Data); + SHELL_FREE_NON_NULL(KeyOptionBuffer); + SHELL_FREE_NON_NULL(FileName); + return ShellStatus; +} + +/** + Function to dump the Bcfg information. + + @param[in] Op The operation. + @param[in] OrderCount How many to dump. + @param[in] CurrentOrder The pointer to the current order of items. + @param[in] VerboseOutput TRUE for extra output. FALSE otherwise. + + @retval SHELL_SUCCESS The dump was successful. + @retval SHELL_INVALID_PARAMETER A parameter was invalid. +**/ +SHELL_STATUS +BcfgDisplayDump( + IN CONST CHAR16 *Op, + IN CONST UINTN OrderCount, + IN CONST UINT16 *CurrentOrder, + IN CONST BOOLEAN VerboseOutput + ) +{ + EFI_STATUS Status; + UINT8 *Buffer; + UINTN BufferSize; + CHAR16 VariableName[12]; + UINTN LoopVar; + CHAR16 *DevPathString; + VOID *FilePathList; + UINTN Errors; + EFI_LOAD_OPTION *LoadOption; + CHAR16 *Description; + UINTN DescriptionSize; + UINTN OptionalDataOffset; + + if (OrderCount == 0) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_BCFG_NONE), gShellBcfgHiiHandle, L"bcfg"); + return (SHELL_SUCCESS); + } + + Errors = 0; + + for (LoopVar = 0 ; LoopVar < OrderCount ; LoopVar++) { + Buffer = NULL; + BufferSize = 0; + DevPathString = NULL; + + UnicodeSPrint(VariableName, sizeof(VariableName), L"%s%04x", Op, CurrentOrder[LoopVar]); + + Status = gRT->GetVariable( + VariableName, + (EFI_GUID*)&gEfiGlobalVariableGuid, + NULL, + &BufferSize, + Buffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + Buffer = AllocateZeroPool(BufferSize); + Status = gRT->GetVariable( + VariableName, + (EFI_GUID*)&gEfiGlobalVariableGuid, + NULL, + &BufferSize, + Buffer); + } + + if (EFI_ERROR(Status) || Buffer == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_READ_FAIL), gShellBcfgHiiHandle, L"bcfg", VariableName); + ++Errors; + goto Cleanup; + } + + // + // We expect the Attributes, FilePathListLength, and L'\0'-terminated + // Description fields to be present. + // + if (BufferSize < sizeof *LoadOption + sizeof (CHAR16)) { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_BCFG_VAR_CORRUPT), + gShellBcfgHiiHandle, + L"bcfg", + VariableName + ); + ++Errors; + goto Cleanup; + } + + LoadOption = (EFI_LOAD_OPTION *)Buffer; + Description = (CHAR16*)(Buffer + sizeof (EFI_LOAD_OPTION)); + DescriptionSize = StrSize (Description); + + if (LoadOption->FilePathListLength != 0) { + FilePathList = (UINT8 *)Description + DescriptionSize; + DevPathString = ConvertDevicePathToText(FilePathList, TRUE, FALSE); + } + + OptionalDataOffset = sizeof *LoadOption + DescriptionSize + + LoadOption->FilePathListLength; + + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN(STR_BCFG_LOAD_OPTIONS), + gShellBcfgHiiHandle, + LoopVar, + VariableName, + Description, + DevPathString, + OptionalDataOffset >= BufferSize ? L'N' : L'Y' + ); + if (VerboseOutput && (OptionalDataOffset < BufferSize)) { + DumpHex ( + 2, // Indent + 0, // Offset (displayed) + BufferSize - OptionalDataOffset, // DataSize + Buffer + OptionalDataOffset // UserData + ); + } + +Cleanup: + if (Buffer != NULL) { + FreePool(Buffer); + } + if (DevPathString != NULL) { + FreePool(DevPathString); + } + } + return (Errors > 0) ? SHELL_INVALID_PARAMETER : SHELL_SUCCESS; +} + +/** + Function to initialize the BCFG operation structure. + + @param[in] Struct The stuct to initialize. +**/ +VOID +InitBcfgStruct( + IN BGFG_OPERATION *Struct + ) +{ + ASSERT(Struct != NULL); + Struct->Target = BcfgTargetMax; + Struct->Type = BcfgTypeMax; + Struct->Number1 = 0; + Struct->Number2 = 0; + Struct->HandleIndex = 0; + Struct->FileName = NULL; + Struct->Description = NULL; + Struct->Order = NULL; + Struct->OptData = NULL; +} + + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-v", TypeFlag}, + {L"-opt", TypeMaxValue}, + {NULL, TypeMax} + }; + +/** + Function for 'bcfg' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunBcfg ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + UINTN ParamNumber; + CONST CHAR16 *CurrentParam; + BGFG_OPERATION CurrentOperation; + UINTN Length; + UINT64 Intermediate; + UINT16 Count; + + Length = 0; + ProblemParam = NULL; + Package = NULL; + ShellStatus = SHELL_SUCCESS; + + InitBcfgStruct(&CurrentOperation); + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellBcfgHiiHandle, L"bcfg", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // Read in if we are doing -OPT + // + if (ShellCommandLineGetFlag(Package, L"-opt")) { + CurrentOperation.OptData = ShellCommandLineGetValue(Package, L"-opt"); + if (CurrentOperation.OptData == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellBcfgHiiHandle, L"bcfg", L"-opt"); + ShellStatus = SHELL_INVALID_PARAMETER; + } + CurrentOperation.Type = BcfgTypeOpt; + } + + // + // small block to read the target of the operation + // + if ((ShellCommandLineGetCount(Package) < 3 && CurrentOperation.Type != BcfgTypeOpt) || + (ShellCommandLineGetCount(Package) < 2 && CurrentOperation.Type == BcfgTypeOpt) + ){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)ShellCommandLineGetRawValue(Package, 1), L"driver") == 0) { + CurrentOperation.Target = BcfgTargetDriverOrder; + } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)ShellCommandLineGetRawValue(Package, 1), L"boot") == 0) { + CurrentOperation.Target = BcfgTargetBootOrder; + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_DRIVER_BOOT), gShellBcfgHiiHandle, L"bcfg"); + ShellStatus = SHELL_INVALID_PARAMETER; + } + + + // + // Read in the boot or driver order environment variable (not needed for opt) + // + if (ShellStatus == SHELL_SUCCESS && CurrentOperation.Target < BcfgTargetMax) { + Length = 0; + Status = gRT->GetVariable( + CurrentOperation.Target == BcfgTargetBootOrder?(CHAR16*)L"BootOrder":(CHAR16*)L"DriverOrder", + (EFI_GUID*)&gEfiGlobalVariableGuid, + NULL, + &Length, + CurrentOperation.Order); + if (Status == EFI_BUFFER_TOO_SMALL) { + CurrentOperation.Order = AllocateZeroPool(Length+(4*sizeof(CurrentOperation.Order[0]))); + if (CurrentOperation.Order == NULL) { + ShellStatus = SHELL_OUT_OF_RESOURCES; + } else { + Status = gRT->GetVariable( + CurrentOperation.Target == BcfgTargetBootOrder?(CHAR16*)L"BootOrder":(CHAR16*)L"DriverOrder", + (EFI_GUID*)&gEfiGlobalVariableGuid, + NULL, + &Length, + CurrentOperation.Order); + } + } + } + + Count = (UINT16) (Length / sizeof(CurrentOperation.Order[0])); + + // + // large block to read the type of operation and verify parameter types for the info. + // + if (ShellStatus == SHELL_SUCCESS && CurrentOperation.Target < BcfgTargetMax) { + for (ParamNumber = 2 ; ParamNumber < ShellCommandLineGetCount(Package) && ShellStatus == SHELL_SUCCESS; ParamNumber++) { + CurrentParam = ShellCommandLineGetRawValue(Package, ParamNumber); + if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)CurrentParam, L"dump") == 0) { + CurrentOperation.Type = BcfgTypeDump; + if (ShellCommandLineGetCount(Package) > 3) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellBcfgHiiHandle, L"bcfg"); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } else if (ShellCommandLineGetFlag(Package, L"-v")) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"-v (without dump)"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)CurrentParam, L"add") == 0) { + if ((ParamNumber + 3) >= ShellCommandLineGetCount(Package)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg"); + ShellStatus = SHELL_INVALID_PARAMETER; + } + CurrentOperation.Type = BcfgTypeAdd; + CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber); + if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE); + CurrentOperation.Number1 = (UINT16)Intermediate; + ASSERT(CurrentOperation.FileName == NULL); + CurrentOperation.FileName = StrnCatGrow(&CurrentOperation.FileName , NULL, ShellCommandLineGetRawValue(Package, ++ParamNumber), 0); + ASSERT(CurrentOperation.Description == NULL); + CurrentOperation.Description = StrnCatGrow(&CurrentOperation.Description, NULL, ShellCommandLineGetRawValue(Package, ++ParamNumber), 0); + } + } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)CurrentParam, L"addp") == 0) { + if ((ParamNumber + 3) >= ShellCommandLineGetCount(Package)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg"); + ShellStatus = SHELL_INVALID_PARAMETER; + } + CurrentOperation.Type = BcfgTypeAddp; + CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber); + if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE); + CurrentOperation.Number1 = (UINT16)Intermediate; + ASSERT(CurrentOperation.FileName == NULL); + CurrentOperation.FileName = StrnCatGrow(&CurrentOperation.FileName , NULL, ShellCommandLineGetRawValue(Package, ++ParamNumber), 0); + ASSERT(CurrentOperation.Description == NULL); + CurrentOperation.Description = StrnCatGrow(&CurrentOperation.Description, NULL, ShellCommandLineGetRawValue(Package, ++ParamNumber), 0); + } + } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)CurrentParam, L"addh") == 0) { + if ((ParamNumber + 3) >= ShellCommandLineGetCount(Package)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg"); + ShellStatus = SHELL_INVALID_PARAMETER; + } + CurrentOperation.Type = BcfgTypeAddh; + CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber); + if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE); + CurrentOperation.Number1 = (UINT16)Intermediate; + CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber); + if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE); + CurrentOperation.HandleIndex = (UINT16)Intermediate; + ASSERT(CurrentOperation.Description == NULL); + CurrentOperation.Description = StrnCatGrow(&CurrentOperation.Description, NULL, ShellCommandLineGetRawValue(Package, ++ParamNumber), 0); + } + } + } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)CurrentParam, L"rm") == 0) { + if ((ParamNumber + 1) >= ShellCommandLineGetCount(Package)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg"); + ShellStatus = SHELL_INVALID_PARAMETER; + } + CurrentOperation.Type = BcfgTypeRm; + CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber); + if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE); + CurrentOperation.Number1 = (UINT16)Intermediate; + if (CurrentOperation.Number1 >= Count){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_NUMB_RANGE), gShellBcfgHiiHandle, L"bcfg", Count); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } + } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)CurrentParam, L"mv") == 0) { + if ((ParamNumber + 2) >= ShellCommandLineGetCount(Package)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg"); + ShellStatus = SHELL_INVALID_PARAMETER; + } + CurrentOperation.Type = BcfgTypeMv; + CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber); + if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE); + CurrentOperation.Number1 = (UINT16)Intermediate; + if (CurrentOperation.Number1 >= Count){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_NUMB_RANGE), gShellBcfgHiiHandle, L"bcfg", Count); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber); + if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE); + CurrentOperation.Number2 = (UINT16)Intermediate; + } + if (CurrentOperation.Number2 == CurrentOperation.Number1 + ||CurrentOperation.Number2 >= Count + ){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_NUMB_RANGE), gShellBcfgHiiHandle, L"bcfg", Count); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } + } + } + else if (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16*)CurrentParam, L"mod") == 0) { + if ((ParamNumber + 2) >= ShellCommandLineGetCount (Package)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + CurrentOperation.Type = BcfgTypeMod; + CurrentParam = ShellCommandLineGetRawValue (Package, ++ParamNumber); + if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber (CurrentParam, TRUE, FALSE)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = ShellConvertStringToUint64 (CurrentParam, &Intermediate, TRUE, FALSE); + CurrentOperation.Number1 = (UINT16)Intermediate; + if (CurrentOperation.Number1 >= Count) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_NUMB_RANGE), gShellBcfgHiiHandle, L"bcfg", Count); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT (CurrentOperation.Description == NULL); + CurrentOperation.Description = StrnCatGrow (&CurrentOperation.Description, NULL, ShellCommandLineGetRawValue (Package, ++ParamNumber), 0); + } + } + } + } else if (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16*)CurrentParam, L"modf") == 0) { + if ((ParamNumber + 2) >= ShellCommandLineGetCount (Package)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + CurrentOperation.Type = BcfgTypeModf; + CurrentParam = ShellCommandLineGetRawValue (Package, ++ParamNumber); + if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber (CurrentParam, TRUE, FALSE)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = ShellConvertStringToUint64 (CurrentParam, &Intermediate, TRUE, FALSE); + CurrentOperation.Number1 = (UINT16)Intermediate; + if (CurrentOperation.Number1 >= Count) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_NUMB_RANGE), gShellBcfgHiiHandle, L"bcfg", Count); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT (CurrentOperation.FileName == NULL); + CurrentOperation.FileName = StrnCatGrow (&CurrentOperation.FileName, NULL, ShellCommandLineGetRawValue (Package, ++ParamNumber), 0); + } + } + } + } else if (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16*)CurrentParam, L"modp") == 0) { + if ((ParamNumber + 2) >= ShellCommandLineGetCount (Package)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + CurrentOperation.Type = BcfgTypeModp; + CurrentParam = ShellCommandLineGetRawValue (Package, ++ParamNumber); + if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber (CurrentParam, TRUE, FALSE)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = ShellConvertStringToUint64 (CurrentParam, &Intermediate, TRUE, FALSE); + CurrentOperation.Number1 = (UINT16)Intermediate; + if (CurrentOperation.Number1 >= Count) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_NUMB_RANGE), gShellBcfgHiiHandle, L"bcfg", Count); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT (CurrentOperation.FileName == NULL); + CurrentOperation.FileName = StrnCatGrow (&CurrentOperation.FileName, NULL, ShellCommandLineGetRawValue (Package, ++ParamNumber), 0); + } + } + } + } else if (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16*)CurrentParam, L"modh") == 0) { + if ((ParamNumber + 2) >= ShellCommandLineGetCount (Package)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + CurrentOperation.Type = BcfgTypeModh; + CurrentParam = ShellCommandLineGetRawValue (Package, ++ParamNumber); + if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber (CurrentParam, TRUE, FALSE)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } + else { + Status = ShellConvertStringToUint64 (CurrentParam, &Intermediate, TRUE, FALSE); + CurrentOperation.Number1 = (UINT16)Intermediate; + if (CurrentOperation.Number1 >= Count) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_NUMB_RANGE), gShellBcfgHiiHandle, L"bcfg", Count); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + CurrentParam = ShellCommandLineGetRawValue (Package, ++ParamNumber); + if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber (CurrentParam, TRUE, FALSE)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = ShellConvertStringToUint64 (CurrentParam, &Intermediate, TRUE, FALSE); + CurrentOperation.HandleIndex = (UINT16)Intermediate; + } + } + } + } + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } + } + if (ShellStatus == SHELL_SUCCESS && CurrentOperation.Target < BcfgTargetMax && CurrentOperation.Type < BcfgTypeMax) { + // + // we have all the info. Do the work + // + switch (CurrentOperation.Type) { + case BcfgTypeDump: + ShellStatus = BcfgDisplayDump( + CurrentOperation.Target == BcfgTargetBootOrder?L"Boot":L"Driver", + Count, + CurrentOperation.Order, + ShellCommandLineGetFlag(Package, L"-v")); + break; + case BcfgTypeMv: + ShellStatus = BcfgMove( + CurrentOperation.Target, + CurrentOperation.Order, + Count, + CurrentOperation.Number1, + CurrentOperation.Number2); + break; + case BcfgTypeRm: + ShellStatus = BcfgRemove( + CurrentOperation.Target, + CurrentOperation.Order, + Count, + CurrentOperation.Number1); + break; + case BcfgTypeAdd: + case BcfgTypeAddp: + case BcfgTypeAddh: + ShellStatus = BcfgAdd( + CurrentOperation.Number1, + CurrentOperation.FileName, + CurrentOperation.Description==NULL?L"":CurrentOperation.Description, + CurrentOperation.Order, + Count, + CurrentOperation.Target, + (BOOLEAN)(CurrentOperation.Type == BcfgTypeAddh), + (BOOLEAN)(CurrentOperation.Type == BcfgTypeAddp), + CurrentOperation.HandleIndex); + break; + case BcfgTypeMod: + case BcfgTypeModf: + case BcfgTypeModp: + case BcfgTypeModh: + ShellStatus = BcfgMod (&CurrentOperation, Count); + break; + case BcfgTypeOpt: + ShellStatus = BcfgAddOpt( + CurrentOperation.OptData, + CurrentOperation.Order, + Count, + CurrentOperation.Target); + break; + default: + ASSERT(FALSE); + } + } + } + + if (Package != NULL) { + ShellCommandLineFreeVarList (Package); + } + if (CurrentOperation.FileName != NULL) { + FreePool(CurrentOperation.FileName); + } + if (CurrentOperation.Description != NULL) { + FreePool(CurrentOperation.Description); + } + if (CurrentOperation.Order != NULL) { + FreePool(CurrentOperation.Order); + } + + return (ShellStatus); +} + + +/** + Function to get the filename with help context if HII will not be used. + + @return The filename with help text in it. +**/ +CONST CHAR16* +EFIAPI +ShellCommandGetManFileNameBcfg ( + VOID + ) +{ + return (mFileName); +} + +/** + "Constructor" for the library. + + This will register the handler for the bcfg command. + + @param[in] ImageHandle the image handle of the process + @param[in] SystemTable the EFI System Table pointer + @param[in] Name the profile name to use + + @retval EFI_SUCCESS the shell command handlers were installed sucessfully + @retval EFI_UNSUPPORTED the shell level required was not found. +**/ +EFI_STATUS +EFIAPI +BcfgLibraryRegisterBcfgCommand ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable, + IN CONST CHAR16 *Name + ) +{ + if (gShellBcfgHiiHandle != NULL) { + return (EFI_SUCCESS); + } + + gShellBcfgHiiHandle = HiiAddPackages (&gShellBcfgHiiGuid, gImageHandle, UefiShellBcfgCommandLibStrings, NULL); + if (gShellBcfgHiiHandle == NULL) { + return (EFI_DEVICE_ERROR); + } + + // + // install our shell command handler + // + ShellCommandRegisterCommandName(L"bcfg", ShellCommandRunBcfg , ShellCommandGetManFileNameBcfg, 0, Name, FALSE, gShellBcfgHiiHandle, STRING_TOKEN(STR_GET_HELP_BCFG)); + + return (EFI_SUCCESS); +} + +/** + Destructor for the library. free any resources. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. +**/ +EFI_STATUS +EFIAPI +BcfgLibraryUnregisterBcfgCommand ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + if (gShellBcfgHiiHandle != NULL) { + HiiRemovePackages(gShellBcfgHiiHandle); + } + gShellBcfgHiiHandle = NULL; + return (EFI_SUCCESS); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf new file mode 100644 index 00000000..5938a9ce --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf @@ -0,0 +1,42 @@ +## @file +# Provides shell install1 functions +# +# Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiShellBcfgCommandLib + FILE_GUID = F6A3BF5D-4095-4E4F-9670-408770C2DBDF + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.1 + LIBRARY_CLASS = BcfgCommandLib|UEFI_APPLICATION UEFI_DRIVER + +[Sources.common] + UefiShellBcfgCommandLib.c + UefiShellBcfgCommandLib.uni + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + ShellCommandLib + ShellLib + UefiLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + SortLib + PrintLib + UefiBootManagerLib + +[Guids] + gShellBcfgHiiGuid ## SOMETIMES_CONSUMES ## HII diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.uni b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.uni new file mode 100644 index 00000000..c8e261ba --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.uni @@ -0,0 +1,153 @@ +// /** +// +// (C) Copyright 2014-2015 Hewlett-Packard Development Company, L.P.
+// Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// Module Name: +// +// UefiBcfgCommandsLib.uni +// +// Abstract: +// +// String definitions for UEFI Shell 2.0 BCFG command +// +// +// **/ + +/=# + +#langdef en-US "english" + +#string STR_GEN_NO_MEM #language en-US "%H%s%N: Memory is not available.\r\n" +#string STR_GEN_PROBLEM #language en-US "%H%s%N: Unknown flag - '%H%s%N'\r\n" +#string STR_GEN_NO_VALUE #language en-US "%H%s%N: Missing argument for flag - '%H%s%N'\r\n" +#string STR_GEN_PARAM_INV #language en-US "%H%s%N: Invalid argument - '%H%s%N'\r\n" +#string STR_GEN_NO_DRIVER_BOOT #language en-US "%H%s%N: Driver or Boot must be selected.\r\n" +#string STR_GEN_BOOT_ONLY #language en-US "%H%s%N: Boot must be selected for hot key options.\r\n" +#string STR_GEN_TOO_FEW #language en-US "%H%s%N: Too few arguments.\r\n" +#string STR_GEN_TOO_MANY #language en-US "%H%s%N: Too many arguments\r\n" +#string STR_GEN_FILE_OPEN_FAIL #language en-US "%H%s%N: Cannot open file - '%H%s%N'\r\n" +#string STR_GEN_FIND_FAIL #language en-US "%H%s%N: File not found - '%H%s%N'\r\n" +#string STR_GEN_OUT_MEM #language en-US "%H%s%N: Memory allocation was not successful.\r\n" +#string STR_BCFG_WRITE_FAIL #language en-US "%H%s%N: Unable to write to '%H%s%N'\r\n" +#string STR_BCFG_READ_FAIL #language en-US "%H%s%N: Unable to read from '%H%s%N'\r\n" +#string STR_BCFG_VAR_CORRUPT #language en-US "%H%s%N: Variable '%H%s%N' corrupt.\r\n" +#string STR_BCFG_HANDLE #language en-US "%H%s%N: The handle [%H%02x%N] does not have DevicePath.\r\n" +#string STR_BCFG_FILE #language en-US "%H%s%N: The file '%H%s%N' matches multiple files.\r\n" +#string STR_BCFG_FILE_OPEN #language en-US "%H%s%N: The file '%H%s%N' did not open.\r\n" +#string STR_BCFG_FILE_DP #language en-US "%H%s%N: The file '%H%s%N' could not convert to DevPath.\r\n" +#string STR_BCFG_TARGET_NF #language en-US "%H%s%N: Could not find unused target index.\r\n" +#string STR_BCFG_TARGET #language en-US "Target = %04x.\r\n" +#string STR_BCFG_SET_VAR_FAIL #language en-US "%H%s%N: Unable to set %H%s%N\r\n" +#string STR_BCFG_VAR_NO_NUM #language en-US "%H%s%N: Cannot create Key#### variable: All the numbers from 0x0000 - 0xFFFF have been used.\r\n" +#string STR_BCFG_NUMB_RANGE #language en-US "%H%s%N: Numbers must be under %d.\r\n" +#string STR_BCFG_NONE #language en-US "No options found.\r\n" + +#string STR_BCFG_LOAD_OPTIONS #language en-US "Option: %B%02x%N. Variable: %B%-11s%N\r\n" + " Desc - %s\r\n" + " DevPath - %s\r\n" + " Optional- %c\r\n" +#string STR_GET_HELP_BCFG #language en-US "" +".TH bcfg 0 "configure boot and driver"\r\n" +".SH NAME\r\n" +"Manages the boot and driver options that are stored in NVRAM.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"BCFG driver|boot [dump [-v]] [add # file "desc"] [addp # file "desc"] \r\n" +" [addh # handle "desc"] [rm #] [mv # #] \r\n" +" [-opt # [[filename]|["data"]] | \r\n" +" [KeyData ]]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -v - Displays verbose information about options, including the optional\r\n" +" data.\r\n" +" -opt - Displays or modifies the optional data associated with a \r\n" +" driver or boot option. This parameter is followed by the file name of the\r\n" +" file that contains the binary data to be associated with the\r\n" +" driver or boot option optional data, or the quote\r\n" +" delimited data to be associated with the driver or\r\n" +" boot option optional data.\r\n" +" driver - Displays or modifies the driver option list.\r\n" +" boot - Displays or modifies the boot option list.\r\n" +" dump - Displays the option list.\r\n" +" add - Adds an option. The # is the number of options to add in\r\n" +" hexadecimal format. The file name is the name of the UEFI application/driver for\r\n" +" the option. The quoted parameter is the description of the\r\n" +" option to be added.\r\n" +" addh - Adds an option that refers to the driver specified by a handle.\r\n" +" The # is the number of options to add, in hexadecimal format. The\r\n" +" handle is the driver handle, in hexadecimal format. The device path\r\n" +" for the option is retrieved from the handle. The quoted\r\n" +" parameter is the description of the option to be added.\r\n" +" addp - Adds an option that refers to a specific file. Only the portion\r\n" +" of the device path starting with the hard drive partition is\r\n" +" placed in the option. The # is the number of options to add,\r\n" +" in hexadecimal format. The quoted parameter is the description of the\r\n" +" option being added.\r\n" +" rm - Removes an option. The parameter lists the number of the options\r\n" +" to remove in hexadecimal format.\r\n" +" mv - Moves an option. The first numeric parameter is the number of\r\n" +" the option to move in hexadecimal format. The second numeric parameter\r\n" +" is the new number of the option to be moved.\r\n" +" KeyData - Specifies the packed value associated with a hot-key.\r\n" +" ScanCode - Specifies the UEFI-defined scan code portion of the\r\n" +" EFI_INPUT_KEY instruction. This value is directly associated\r\n" +" with the preceding KeyData value. When one instance of this\r\n" +" parameter has a non-zero value, the paired UnicodeChar value\r\n" +" will have a zero-based value.\r\n" +" UnicodeChar - Specifies the Unicode value for the character associated with\r\n" +" the preceding KeyData value. When one instance of this\r\n" +" parameter has a non-zero value, the paired ScanCode value\r\n" +" will have a zero-based value.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command manages the boot and driver options stored in NVRAM.\r\n" +" 2. Use the dump option to display Boot#### or Driver#### environment variables.\r\n" +" 3. Use the add option to add a new Boot#### or Driver#### \r\n" +" environment variable.\r\n" +" 4. Use the rm option to delete a Boot#### or Driver#### \r\n" +" environment variable, and then the mv option to reorder\r\n" +" the Boot#### and Driver#### environment variables.\r\n" +" 5. The add, rm, and mv options also update the BootOrder or DriverOrder\r\n" +" environment variables, as appropriate.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display driver options:\r\n" +" Shell> bcfg driver dump\r\n" +" \r\n" +" * To display boot options:\r\n" +" Shell> bcfg boot dump\r\n" +" \r\n" +" * To display verbose information about boot options:\r\n" +" Shell> bcfg boot dump -v\r\n" +" \r\n" +" * To add a driver option #5:\r\n" +" Shell> bcfg driver add 5 mydriver.efi "My Driver"\r\n" +" \r\n" +" * To add a boot option #3:\r\n" +" Shell> bcfg boot add 3 osloader.efi "My OS"\r\n" +" \r\n" +" * To remove boot option #3:\r\n" +" Shell> bcfg boot rm 3\r\n" +" \r\n" +" * To move boot option #3 to boot option #7:\r\n" +" Shell> bcfg boot mv 3 7\r\n" +" \r\n" +" * To assign a CTRL-B hot-key to boot option #3:\r\n" +" Shell> bcfg boot -opt 3 0x40000200 0 0x42\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_NOT_FOUND The requested option was not found.\r\n" +" SHELL_INVALID_PARAMETER One of the passed-in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" +" SHELL_UNSUPPORTED The action as requested was unsupported.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_OUT_OF_RESOURCES There was insufficient free space for the request\r\n" +" to be completed.\r\n" + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.c new file mode 100644 index 00000000..c581dd9d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.c @@ -0,0 +1,93 @@ +/** @file + Provides application point extension for "C" style main function + + Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include +#include +#include +#include + +#include +#include + +/** + UEFI entry point for an application that will in turn call the + ShellAppMain function which has parameters similar to a standard C + main function. + + An application that uses UefiShellCEntryLib must have a ShellAppMain + function as prototyped in Include/Library/ShellCEntryLib.h. + + Note that the Shell uses POSITIVE integers for error values, while UEFI + uses NEGATIVE values. If the application is to be used within a script, + it needs to return one of the SHELL_STATUS values defined in Protocol/Shell.h. + + @param ImageHandle The image handle of the UEFI Application. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The application exited normally. + @retval Other An error occurred. + +**/ +EFI_STATUS +EFIAPI +ShellCEntryLib ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + INTN ReturnFromMain; + EFI_SHELL_PARAMETERS_PROTOCOL *EfiShellParametersProtocol; + EFI_SHELL_INTERFACE *EfiShellInterface; + EFI_STATUS Status; + + ReturnFromMain = -1; + EfiShellParametersProtocol = NULL; + EfiShellInterface = NULL; + + Status = SystemTable->BootServices->OpenProtocol(ImageHandle, + &gEfiShellParametersProtocolGuid, + (VOID **)&EfiShellParametersProtocol, + ImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR(Status)) { + // + // use shell 2.0 interface + // + ReturnFromMain = ShellAppMain ( + EfiShellParametersProtocol->Argc, + EfiShellParametersProtocol->Argv + ); + } else { + // + // try to get shell 1.0 interface instead. + // + Status = SystemTable->BootServices->OpenProtocol(ImageHandle, + &gEfiShellInterfaceGuid, + (VOID **)&EfiShellInterface, + ImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR(Status)) { + // + // use shell 1.0 interface + // + ReturnFromMain = ShellAppMain ( + EfiShellInterface->Argc, + EfiShellInterface->Argv + ); + } else { + ASSERT(FALSE); + } + } + return ReturnFromMain; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf new file mode 100644 index 00000000..9c1cabd4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf @@ -0,0 +1,39 @@ +## @file +# Provides interface to shell functionality for shell commands and applications. +# +# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiShellCEntryLib + FILE_GUID = 0e205c8a-8586-4dec-9f5c-4f9e394aefe8 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + LIBRARY_CLASS = ShellCEntryLib|UEFI_APPLICATION UEFI_DRIVER + +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources.common] + UefiShellCEntryLib.c + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + +[LibraryClasses] + UefiApplicationEntryPoint + DebugLib + + +[Protocols] + gEfiShellParametersProtocolGuid ## CONSUMES + gEfiShellInterfaceGuid ## SOMETIMES_CONSUMES + + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellCommandLib/ConsistMapping.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellCommandLib/ConsistMapping.c new file mode 100644 index 00000000..bdff94ab --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellCommandLib/ConsistMapping.c @@ -0,0 +1,1692 @@ +/** @file + Main file for support of shell consist mapping. + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "UefiShellCommandLib.h" +#include +#include +#include +#include +#include +#include + + + +typedef enum { + MTDTypeUnknown, + MTDTypeFloppy, + MTDTypeHardDisk, + MTDTypeCDRom, + MTDTypeEnd +} MTD_TYPE; + +typedef struct { + CHAR16 *Str; + UINTN Len; +} POOL_PRINT; + +typedef struct { + UINTN Hi; + MTD_TYPE Mtd; + POOL_PRINT Csd; + BOOLEAN Digital; +} DEVICE_CONSIST_MAPPING_INFO; + +typedef struct { + MTD_TYPE MTDType; + CHAR16 *Name; +} MTD_NAME; + +/** + Serial Decode function. + + @param DevPath The Device path info. + @param MapInfo The map info. + @param OrigDevPath The original device path protocol. + + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_SUCCESS The appending was successful. +**/ +typedef +EFI_STATUS +(*SERIAL_DECODE_FUNCTION) ( + EFI_DEVICE_PATH_PROTOCOL *DevPath, + DEVICE_CONSIST_MAPPING_INFO *MapInfo, + EFI_DEVICE_PATH_PROTOCOL *OrigDevPath + ); + +typedef struct { + UINT8 Type; + UINT8 SubType; + SERIAL_DECODE_FUNCTION SerialFun; + INTN (EFIAPI *CompareFun) (EFI_DEVICE_PATH_PROTOCOL *DevPath, EFI_DEVICE_PATH_PROTOCOL *DevPath2); +} DEV_PATH_CONSIST_MAPPING_TABLE; + + +/** + Concatenates a formatted unicode string to allocated pool. + The caller must free the resulting buffer. + + @param Str Tracks the allocated pool, size in use, and amount of pool allocated. + @param Fmt The format string + @param ... The data will be printed. + + @retval EFI_SUCCESS The string is concatenated successfully. + @retval EFI_OUT_OF_RESOURCES Out of resources. + +**/ +EFI_STATUS +EFIAPI +CatPrint ( + IN OUT POOL_PRINT *Str, + IN CHAR16 *Fmt, + ... + ) +{ + UINT16 *AppendStr; + VA_LIST Args; + UINTN StringSize; + CHAR16 *NewStr; + + AppendStr = AllocateZeroPool (0x1000); + if (AppendStr == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + VA_START (Args, Fmt); + UnicodeVSPrint (AppendStr, 0x1000, Fmt, Args); + VA_END (Args); + if (NULL == Str->Str) { + StringSize = StrSize (AppendStr); + NewStr = AllocateZeroPool (StringSize); + } else { + StringSize = StrSize (AppendStr); + StringSize += (StrSize (Str->Str) - sizeof (UINT16)); + + NewStr = ReallocatePool ( + StrSize (Str->Str), + StringSize, + Str->Str + ); + } + if (NewStr == NULL) { + FreePool (AppendStr); + return EFI_OUT_OF_RESOURCES; + } + + Str->Str = NewStr; + StrCatS (Str->Str, StringSize/sizeof(CHAR16), AppendStr); + Str->Len = StringSize; + + FreePool (AppendStr); + return EFI_SUCCESS; +} + +MTD_NAME mMTDName[] = { + { + MTDTypeUnknown, + L"F" + }, + { + MTDTypeFloppy, + L"FP" + }, + { + MTDTypeHardDisk, + L"HD" + }, + { + MTDTypeCDRom, + L"CD" + }, + { + MTDTypeEnd, + NULL + } +}; + +/** + Function to append a 64 bit number / 25 onto the string. + + @param[in, out] Str The string so append onto. + @param[in] Num The number to divide and append. + + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_SUCCESS The appending was successful. +**/ +EFI_STATUS +AppendCSDNum2 ( + IN OUT POOL_PRINT *Str, + IN UINT64 Num + ) +{ + EFI_STATUS Status; + UINT64 Result; + UINT32 Rem; + + ASSERT (Str != NULL); + + Result = DivU64x32Remainder (Num, 25, &Rem); + if (Result > 0) { + Status = AppendCSDNum2 (Str, Result); + if (EFI_ERROR (Status)) { + return Status; + } + } + + return CatPrint (Str, L"%c", Rem + 'a'); +} + +/** + Function to append a 64 bit number onto the mapping info. + + @param[in, out] MappingItem The mapping info object to append onto. + @param[in] Num The info to append. + + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_SUCCESS The appending was successful. + +**/ +EFI_STATUS +AppendCSDNum ( + IN OUT DEVICE_CONSIST_MAPPING_INFO *MappingItem, + IN UINT64 Num + ) +{ + EFI_STATUS Status; + ASSERT (MappingItem != NULL); + + if (MappingItem->Digital) { + Status = CatPrint (&MappingItem->Csd, L"%ld", Num); + } else { + Status = AppendCSDNum2 (&MappingItem->Csd, Num); + } + + if (!EFI_ERROR (Status)) { + MappingItem->Digital = (BOOLEAN) !(MappingItem->Digital); + } + + return Status; +} + +/** + Function to append string into the mapping info. + + @param[in, out] MappingItem The mapping info object to append onto. + @param[in] Str The info to append. + + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_SUCCESS The appending was successful. +**/ +EFI_STATUS +AppendCSDStr ( + IN OUT DEVICE_CONSIST_MAPPING_INFO *MappingItem, + IN CHAR16 *Str + ) +{ + CHAR16 *Index; + EFI_STATUS Status; + + ASSERT (Str != NULL && MappingItem != NULL); + + Status = EFI_SUCCESS; + + if (MappingItem->Digital) { + // + // To aVOID mult-meaning, the mapping is: + // 0 1 2 3 4 5 6 7 8 9 a b c d e f + // 0 16 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + // + for (Index = Str; *Index != 0; Index++) { + switch (*Index) { + case '0': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + Status = CatPrint (&MappingItem->Csd, L"%c", *Index); + break; + + case '1': + Status = CatPrint (&MappingItem->Csd, L"16"); + break; + + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + Status = CatPrint (&MappingItem->Csd, L"1%c", *Index - 'a' + '0'); + break; + + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + Status = CatPrint (&MappingItem->Csd, L"1%c", *Index - 'A' + '0'); + break; + } + + if (EFI_ERROR (Status)) { + return Status; + } + } + } else { + for (Index = Str; *Index != 0; Index++) { + // + // The mapping is: + // 0 1 2 3 4 5 6 7 8 9 a b c d e f + // a b c d e f g h i j k l m n o p + // + if (*Index >= '0' && *Index <= '9') { + Status = CatPrint (&MappingItem->Csd, L"%c", *Index - '0' + 'a'); + } else if (*Index >= 'a' && *Index <= 'f') { + Status = CatPrint (&MappingItem->Csd, L"%c", *Index - 'a' + 'k'); + } else if (*Index >= 'A' && *Index <= 'F') { + Status = CatPrint (&MappingItem->Csd, L"%c", *Index - 'A' + 'k'); + } + + if (EFI_ERROR (Status)) { + return Status; + } + } + } + + MappingItem->Digital = (BOOLEAN)!(MappingItem->Digital); + + return (EFI_SUCCESS); +} + +/** + Function to append a Guid to the mapping item. + + @param[in, out] MappingItem The item to append onto. + @param[in] Guid The guid to append. + + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_SUCCESS The appending was successful. +**/ +EFI_STATUS +AppendCSDGuid ( + DEVICE_CONSIST_MAPPING_INFO *MappingItem, + EFI_GUID *Guid + ) +{ + CHAR16 Buffer[64]; + + ASSERT (Guid != NULL && MappingItem != NULL); + + UnicodeSPrint ( + Buffer, + 0, + L"%g", + Guid + ); + + return AppendCSDStr (MappingItem, Buffer); +} + +/** + Function to compare 2 APCI device paths. + + @param[in] DevicePath1 The first device path to compare. + @param[in] DevicePath2 The second device path to compare. + + @retval 0 The device paths represent the same device. + @return Non zero if the devices are different, zero otherwise. +**/ +INTN +EFIAPI +DevPathCompareAcpi ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath1, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath2 + ) +{ + ACPI_HID_DEVICE_PATH *Acpi1; + ACPI_HID_DEVICE_PATH *Acpi2; + + if (DevicePath1 == NULL || DevicePath2 == NULL) { + return (-2); + } + + Acpi1 = (ACPI_HID_DEVICE_PATH *) DevicePath1; + Acpi2 = (ACPI_HID_DEVICE_PATH *) DevicePath2; + if (Acpi1->HID > Acpi2->HID || (Acpi1->HID == Acpi2->HID && Acpi1->UID > Acpi2->UID)) { + return 1; + } + + if (Acpi1->HID == Acpi2->HID && Acpi1->UID == Acpi2->UID) { + return 0; + } + + return -1; +} + +/** + Function to compare 2 PCI device paths. + + @param[in] DevicePath1 The first device path to compare. + @param[in] DevicePath2 The second device path to compare. + + @retval 0 The device paths represent the same device. + @return Non zero if the devices are different, zero otherwise. +**/ +INTN +EFIAPI +DevPathComparePci ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath1, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath2 + ) +{ + PCI_DEVICE_PATH *Pci1; + PCI_DEVICE_PATH *Pci2; + + ASSERT(DevicePath1 != NULL); + ASSERT(DevicePath2 != NULL); + + Pci1 = (PCI_DEVICE_PATH *) DevicePath1; + Pci2 = (PCI_DEVICE_PATH *) DevicePath2; + if (Pci1->Device > Pci2->Device || (Pci1->Device == Pci2->Device && Pci1->Function > Pci2->Function)) { + return 1; + } + + if (Pci1->Device == Pci2->Device && Pci1->Function == Pci2->Function) { + return 0; + } + + return -1; +} + +/** + Do a comparison on 2 device paths. + + @param[in] DevicePath1 The first device path. + @param[in] DevicePath2 The second device path. + + @retval 0 The 2 device paths are the same. + @retval <0 DevicePath2 is greater than DevicePath1. + @retval >0 DevicePath1 is greater than DevicePath2. +**/ +INTN +EFIAPI +DevPathCompareDefault ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath1, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath2 + ) +{ + UINTN DevPathSize1; + UINTN DevPathSize2; + + ASSERT(DevicePath1 != NULL); + ASSERT(DevicePath2 != NULL); + + DevPathSize1 = DevicePathNodeLength (DevicePath1); + DevPathSize2 = DevicePathNodeLength (DevicePath2); + if (DevPathSize1 > DevPathSize2) { + return 1; + } else if (DevPathSize1 < DevPathSize2) { + return -1; + } else { + return CompareMem (DevicePath1, DevicePath2, DevPathSize1); + } +} + +/** + DevicePathNode must be SerialHDD Channel type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. + @param[in] DevicePath Ignored. + + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_SUCCESS The appending was successful. +**/ +EFI_STATUS +DevPathSerialHardDrive ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + HARDDRIVE_DEVICE_PATH *Hd; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Hd = (HARDDRIVE_DEVICE_PATH *) DevicePathNode; + if (MappingItem->Mtd == MTDTypeUnknown) { + MappingItem->Mtd = MTDTypeHardDisk; + } + + return AppendCSDNum (MappingItem, Hd->PartitionNumber); +} + +/** + DevicePathNode must be SerialAtapi Channel type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. + @param[in] DevicePath Ignored. + + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_SUCCESS The appending was successful. +**/ +EFI_STATUS +DevPathSerialAtapi ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + ATAPI_DEVICE_PATH *Atapi; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Atapi = (ATAPI_DEVICE_PATH *) DevicePathNode; + return AppendCSDNum (MappingItem, (Atapi->PrimarySecondary * 2 + Atapi->SlaveMaster)); +} + +/** + DevicePathNode must be SerialCDROM Channel type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. + @param[in] DevicePath Ignored. + + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_SUCCESS The appending was successful. +**/ +EFI_STATUS +DevPathSerialCdRom ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + CDROM_DEVICE_PATH *Cd; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Cd = (CDROM_DEVICE_PATH *) DevicePathNode; + MappingItem->Mtd = MTDTypeCDRom; + return AppendCSDNum (MappingItem, Cd->BootEntry); +} + +/** + DevicePathNode must be SerialFibre Channel type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. + @param[in] DevicePath Ignored. + + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_SUCCESS The appending was successful. +**/ +EFI_STATUS +DevPathSerialFibre ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_STATUS Status; + FIBRECHANNEL_DEVICE_PATH *Fibre; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Fibre = (FIBRECHANNEL_DEVICE_PATH *) DevicePathNode; + Status = AppendCSDNum (MappingItem, Fibre->WWN); + if (!EFI_ERROR (Status)) { + Status = AppendCSDNum (MappingItem, Fibre->Lun); + } + return Status; +} + +/** + DevicePathNode must be SerialUart type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. + @param[in] DevicePath Ignored. + + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_SUCCESS The appending was successful. +**/ +EFI_STATUS +DevPathSerialUart ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_STATUS Status; + UART_DEVICE_PATH *Uart; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Uart = (UART_DEVICE_PATH *) DevicePathNode; + Status = AppendCSDNum (MappingItem, Uart->BaudRate); + if (!EFI_ERROR (Status)) { + Status = AppendCSDNum (MappingItem, Uart->DataBits); + } + if (!EFI_ERROR (Status)) { + Status = AppendCSDNum (MappingItem, Uart->Parity); + } + if (!EFI_ERROR (Status)) { + Status = AppendCSDNum (MappingItem, Uart->StopBits); + } + return Status; +} + +/** + DevicePathNode must be SerialUSB type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. + @param[in] DevicePath Ignored. + + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_SUCCESS The appending was successful. +**/ +EFI_STATUS +DevPathSerialUsb ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + USB_DEVICE_PATH *Usb; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_HANDLE TempHandle; + EFI_STATUS Status; + USB_INTERFACE_DESCRIPTOR InterfaceDesc; + + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Usb = (USB_DEVICE_PATH *) DevicePathNode; + Status = AppendCSDNum (MappingItem, Usb->ParentPortNumber); + if (!EFI_ERROR (Status)) { + Status = AppendCSDNum (MappingItem, Usb->InterfaceNumber); + } + + if (EFI_ERROR (Status)) { + return Status; + } + + if (PcdGetBool(PcdUsbExtendedDecode)) { + Status = gBS->LocateDevicePath( &gEfiUsbIoProtocolGuid, &DevicePath, &TempHandle ); + UsbIo = NULL; + if (!EFI_ERROR(Status)) { + Status = gBS->OpenProtocol(TempHandle, &gEfiUsbIoProtocolGuid, (VOID**)&UsbIo, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + } + + if (!EFI_ERROR(Status)) { + ASSERT(UsbIo != NULL); + Status = UsbIo->UsbGetInterfaceDescriptor(UsbIo, &InterfaceDesc); + if (!EFI_ERROR(Status)) { + if (InterfaceDesc.InterfaceClass == USB_MASS_STORE_CLASS && MappingItem->Mtd == MTDTypeUnknown) { + switch (InterfaceDesc.InterfaceSubClass){ + case USB_MASS_STORE_SCSI: + MappingItem->Mtd = MTDTypeHardDisk; + break; + case USB_MASS_STORE_8070I: + case USB_MASS_STORE_UFI: + MappingItem->Mtd = MTDTypeFloppy; + break; + case USB_MASS_STORE_8020I: + MappingItem->Mtd = MTDTypeCDRom; + break; + } + } + } + } + } + return Status; +} + +/** + DevicePathNode must be SerialVendor type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. + @param[in] DevicePath Ignored. + + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_SUCCESS The appending was successful. +**/ +EFI_STATUS +DevPathSerialVendor ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_STATUS Status; + VENDOR_DEVICE_PATH *Vendor; + SAS_DEVICE_PATH *Sas; + UINTN TargetNameLength; + UINTN Index; + CHAR16 *Buffer; + CHAR16 *NewBuffer; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Vendor = (VENDOR_DEVICE_PATH *) DevicePathNode; + Status = AppendCSDGuid (MappingItem, &Vendor->Guid); + if (EFI_ERROR (Status)) { + return Status; + } + + if (CompareGuid (&gEfiSasDevicePathGuid, &Vendor->Guid)) { + Sas = (SAS_DEVICE_PATH *) Vendor; + Status = AppendCSDNum (MappingItem, Sas->SasAddress); + if (!EFI_ERROR (Status)) { + Status = AppendCSDNum (MappingItem, Sas->Lun); + } + if (!EFI_ERROR (Status)) { + Status = AppendCSDNum (MappingItem, Sas->DeviceTopology); + } + if (!EFI_ERROR (Status)) { + Status = AppendCSDNum (MappingItem, Sas->RelativeTargetPort); + } + } else { + TargetNameLength = MIN(DevicePathNodeLength (DevicePathNode) - sizeof (VENDOR_DEVICE_PATH), PcdGet32(PcdShellVendorExtendedDecode)); + if (TargetNameLength != 0) { + // + // String is 2 chars per data byte, plus NULL terminator + // + Buffer = AllocateZeroPool (((TargetNameLength * 2) + 1) * sizeof(CHAR16)); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Build the string data + // + for (Index = 0; Index < TargetNameLength; Index++) { + NewBuffer = CatSPrint (Buffer, L"%02x", *((UINT8*)Vendor + sizeof (VENDOR_DEVICE_PATH) + Index)); + if (NewBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + break; + } + Buffer = NewBuffer; + } + + // + // Append the new data block + // + if (!EFI_ERROR (Status)) { + Status = AppendCSDStr (MappingItem, Buffer); + } + + FreePool(Buffer); + } + } + return Status; +} + +/** + DevicePathNode must be SerialLun type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. + @param[in] DevicePath Ignored. + + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_SUCCESS The appending was successful. +**/ +EFI_STATUS +DevPathSerialLun ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + DEVICE_LOGICAL_UNIT_DEVICE_PATH *Lun; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Lun = (DEVICE_LOGICAL_UNIT_DEVICE_PATH *) DevicePathNode; + return AppendCSDNum (MappingItem, Lun->Lun); +} + +/** + DevicePathNode must be SerialSata type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. + @param[in] DevicePath Ignored. + + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_SUCCESS The appending was successful. +**/ +EFI_STATUS +DevPathSerialSata ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_STATUS Status; + SATA_DEVICE_PATH *Sata; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Sata = (SATA_DEVICE_PATH *) DevicePathNode; + Status = AppendCSDNum (MappingItem, Sata->HBAPortNumber); + if (!EFI_ERROR (Status)) { + Status = AppendCSDNum (MappingItem, Sata->PortMultiplierPortNumber); + } + if (!EFI_ERROR (Status)) { + Status = AppendCSDNum (MappingItem, Sata->Lun); + } + return Status; +} + +/** + DevicePathNode must be SerialSCSI type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. + @param[in] DevicePath Ignored. + + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_SUCCESS The appending was successful. +**/ +EFI_STATUS +DevPathSerialIScsi ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_STATUS Status; + ISCSI_DEVICE_PATH *IScsi; + UINT8 *IScsiTargetName; + CHAR16 *TargetName; + UINTN TargetNameLength; + UINTN Index; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Status = EFI_SUCCESS; + + if (PcdGetBool(PcdShellDecodeIScsiMapNames)) { + IScsi = (ISCSI_DEVICE_PATH *) DevicePathNode; + Status = AppendCSDNum (MappingItem, IScsi->NetworkProtocol); + if (!EFI_ERROR (Status)) { + Status = AppendCSDNum (MappingItem, IScsi->LoginOption); + } + if (!EFI_ERROR (Status)) { + Status = AppendCSDNum (MappingItem, IScsi->Lun); + } + if (!EFI_ERROR (Status)) { + Status = AppendCSDNum (MappingItem, IScsi->TargetPortalGroupTag); + } + if (EFI_ERROR (Status)) { + return Status; + } + TargetNameLength = DevicePathNodeLength (DevicePathNode) - sizeof (ISCSI_DEVICE_PATH); + if (TargetNameLength > 0) { + TargetName = AllocateZeroPool ((TargetNameLength + 1) * sizeof (CHAR16)); + if (TargetName == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + IScsiTargetName = (UINT8 *) (IScsi + 1); + for (Index = 0; Index < TargetNameLength; Index++) { + TargetName[Index] = (CHAR16) IScsiTargetName[Index]; + } + Status = AppendCSDStr (MappingItem, TargetName); + FreePool (TargetName); + } + } + } + return Status; +} + +/** + DevicePathNode must be SerialI20 type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. + @param[in] DevicePath Ignored. + + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_SUCCESS The appending was successful. +**/ +EFI_STATUS +DevPathSerialI2O ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + I2O_DEVICE_PATH *DevicePath_I20; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + DevicePath_I20 = (I2O_DEVICE_PATH *) DevicePathNode; + return AppendCSDNum (MappingItem, DevicePath_I20->Tid); +} + +/** + DevicePathNode must be Mac Address type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. + @param[in] DevicePath Ignored. + + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_SUCCESS The appending was successful. +**/ +EFI_STATUS +DevPathSerialMacAddr ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + MAC_ADDR_DEVICE_PATH *Mac; + UINTN HwAddressSize; + UINTN Index; + CHAR16 Buffer[64]; + CHAR16 *PBuffer; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Mac = (MAC_ADDR_DEVICE_PATH *) DevicePathNode; + + HwAddressSize = sizeof (EFI_MAC_ADDRESS); + if (Mac->IfType == 0x01 || Mac->IfType == 0x00) { + HwAddressSize = 6; + } + + for (Index = 0, PBuffer = Buffer; Index < HwAddressSize; Index++, PBuffer += 2) { + UnicodeSPrint (PBuffer, 0, L"%02x", (UINTN) Mac->MacAddress.Addr[Index]); + } + + return AppendCSDStr (MappingItem, Buffer); +} + +/** + DevicePathNode must be InfiniBand type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. + @param[in] DevicePath Ignored. + + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_SUCCESS The appending was successful. +**/ +EFI_STATUS +DevPathSerialInfiniBand ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_STATUS Status; + INFINIBAND_DEVICE_PATH *InfiniBand; + UINTN Index; + CHAR16 Buffer[64]; + CHAR16 *PBuffer; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + InfiniBand = (INFINIBAND_DEVICE_PATH *) DevicePathNode; + for (Index = 0, PBuffer = Buffer; Index < 16; Index++, PBuffer += 2) { + UnicodeSPrint (PBuffer, 0, L"%02x", (UINTN) InfiniBand->PortGid[Index]); + } + + Status = AppendCSDStr (MappingItem, Buffer); + if (!EFI_ERROR (Status)) { + Status = AppendCSDNum (MappingItem, InfiniBand->ServiceId); + } + if (!EFI_ERROR (Status)) { + Status = AppendCSDNum (MappingItem, InfiniBand->TargetPortId); + } + if (!EFI_ERROR (Status)) { + Status = AppendCSDNum (MappingItem, InfiniBand->DeviceId); + } + return Status; +} + +/** + DevicePathNode must be IPv4 type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. + @param[in] DevicePath Ignored. + + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_SUCCESS The appending was successful. +**/ +EFI_STATUS +DevPathSerialIPv4 ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_STATUS Status; + IPv4_DEVICE_PATH *Ip; + CHAR16 Buffer[10]; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Ip = (IPv4_DEVICE_PATH *) DevicePathNode; + UnicodeSPrint ( + Buffer, + 0, + L"%02x%02x%02x%02x", + (UINTN) Ip->LocalIpAddress.Addr[0], + (UINTN) Ip->LocalIpAddress.Addr[1], + (UINTN) Ip->LocalIpAddress.Addr[2], + (UINTN) Ip->LocalIpAddress.Addr[3] + ); + Status = AppendCSDStr (MappingItem, Buffer); + if (!EFI_ERROR (Status)) { + Status = AppendCSDNum (MappingItem, Ip->LocalPort); + } + if (!EFI_ERROR (Status)) { + UnicodeSPrint ( + Buffer, + 0, + L"%02x%02x%02x%02x", + (UINTN) Ip->RemoteIpAddress.Addr[0], + (UINTN) Ip->RemoteIpAddress.Addr[1], + (UINTN) Ip->RemoteIpAddress.Addr[2], + (UINTN) Ip->RemoteIpAddress.Addr[3] + ); + Status = AppendCSDStr (MappingItem, Buffer); + } + if (!EFI_ERROR (Status)) { + Status = AppendCSDNum (MappingItem, Ip->RemotePort); + } + return Status; +} + +/** + DevicePathNode must be IPv6 type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. + @param[in] DevicePath Ignored. + + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_SUCCESS The appending was successful. +**/ +EFI_STATUS +DevPathSerialIPv6 ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_STATUS Status; + IPv6_DEVICE_PATH *Ip; + UINTN Index; + CHAR16 Buffer[64]; + CHAR16 *PBuffer; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Ip = (IPv6_DEVICE_PATH *) DevicePathNode; + for (Index = 0, PBuffer = Buffer; Index < 16; Index++, PBuffer += 2) { + UnicodeSPrint (PBuffer, 0, L"%02x", (UINTN) Ip->LocalIpAddress.Addr[Index]); + } + + Status = AppendCSDStr (MappingItem, Buffer); + if (!EFI_ERROR (Status)) { + Status = AppendCSDNum (MappingItem, Ip->LocalPort); + } + if (!EFI_ERROR (Status)) { + for (Index = 0, PBuffer = Buffer; Index < 16; Index++, PBuffer += 2) { + UnicodeSPrint (PBuffer, 0, L"%02x", (UINTN) Ip->RemoteIpAddress.Addr[Index]); + } + + Status = AppendCSDStr (MappingItem, Buffer); + } + if (!EFI_ERROR (Status)) { + Status = AppendCSDNum (MappingItem, Ip->RemotePort); + } + return Status; +} + +/** + DevicePathNode must be SCSI type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. + @param[in] DevicePath Ignored. + + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_SUCCESS The appending was successful. +**/ +EFI_STATUS +DevPathSerialScsi ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_STATUS Status; + SCSI_DEVICE_PATH *Scsi; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Scsi = (SCSI_DEVICE_PATH *) DevicePathNode; + Status = AppendCSDNum (MappingItem, Scsi->Pun); + if (!EFI_ERROR (Status)) { + Status = AppendCSDNum (MappingItem, Scsi->Lun); + } + return Status; +} + +/** + DevicePathNode must be 1394 type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. + @param[in] DevicePath Ignored. + + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_SUCCESS The appending was successful. +**/ +EFI_STATUS +DevPathSerial1394 ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + F1394_DEVICE_PATH *DevicePath_F1394; + CHAR16 Buffer[20]; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + DevicePath_F1394 = (F1394_DEVICE_PATH *) DevicePathNode; + UnicodeSPrint (Buffer, 0, L"%lx", DevicePath_F1394->Guid); + return AppendCSDStr (MappingItem, Buffer); +} + +/** + If the node is floppy type then populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. + @param[in] DevicePath Ignored. + + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_SUCCESS The appending was successful. +**/ +EFI_STATUS +DevPathSerialAcpi ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + ACPI_HID_DEVICE_PATH *Acpi; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Acpi = (ACPI_HID_DEVICE_PATH *) DevicePathNode; + if ((Acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { + if (EISA_ID_TO_NUM (Acpi->HID) == 0x0604) { + MappingItem->Mtd = MTDTypeFloppy; + return AppendCSDNum (MappingItem, Acpi->UID); + } + } + return EFI_SUCCESS; +} + +/** + Empty function used for unknown devices. + + @param[in] DevicePathNode Ignored. + @param[in] MappingItem Ignored. + @param[in] DevicePath Ignored. + + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_SUCCESS The appending was successful. +**/ +EFI_STATUS +DevPathSerialDefault ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + return EFI_SUCCESS; +} + +DEV_PATH_CONSIST_MAPPING_TABLE DevPathConsistMappingTable[] = { + { + HARDWARE_DEVICE_PATH, + HW_PCI_DP, + DevPathSerialDefault, + DevPathComparePci + }, + { + ACPI_DEVICE_PATH, + ACPI_DP, + DevPathSerialAcpi, + DevPathCompareAcpi + }, + { + MESSAGING_DEVICE_PATH, + MSG_ATAPI_DP, + DevPathSerialAtapi, + DevPathCompareDefault + }, + { + MESSAGING_DEVICE_PATH, + MSG_SCSI_DP, + DevPathSerialScsi, + DevPathCompareDefault + }, + { + MESSAGING_DEVICE_PATH, + MSG_FIBRECHANNEL_DP, + DevPathSerialFibre, + DevPathCompareDefault + }, + { + MESSAGING_DEVICE_PATH, + MSG_1394_DP, + DevPathSerial1394, + DevPathCompareDefault + }, + { + MESSAGING_DEVICE_PATH, + MSG_USB_DP, + DevPathSerialUsb, + DevPathCompareDefault + }, + { + MESSAGING_DEVICE_PATH, + MSG_I2O_DP, + DevPathSerialI2O, + DevPathCompareDefault + }, + { + MESSAGING_DEVICE_PATH, + MSG_MAC_ADDR_DP, + DevPathSerialMacAddr, + DevPathCompareDefault + }, + { + MESSAGING_DEVICE_PATH, + MSG_IPv4_DP, + DevPathSerialIPv4, + DevPathCompareDefault + }, + { + MESSAGING_DEVICE_PATH, + MSG_IPv6_DP, + DevPathSerialIPv6, + DevPathCompareDefault + }, + { + MESSAGING_DEVICE_PATH, + MSG_INFINIBAND_DP, + DevPathSerialInfiniBand, + DevPathCompareDefault + }, + { + MESSAGING_DEVICE_PATH, + MSG_UART_DP, + DevPathSerialUart, + DevPathCompareDefault + }, + { + MESSAGING_DEVICE_PATH, + MSG_VENDOR_DP, + DevPathSerialVendor, + DevPathCompareDefault + }, + { + MESSAGING_DEVICE_PATH, + MSG_DEVICE_LOGICAL_UNIT_DP, + DevPathSerialLun, + DevPathCompareDefault + }, + { + MESSAGING_DEVICE_PATH, + MSG_SATA_DP, + DevPathSerialSata, + DevPathCompareDefault + }, + { + MESSAGING_DEVICE_PATH, + MSG_ISCSI_DP, + DevPathSerialIScsi, + DevPathCompareDefault + }, + { + MEDIA_DEVICE_PATH, + MEDIA_HARDDRIVE_DP, + DevPathSerialHardDrive, + DevPathCompareDefault + }, + { + MEDIA_DEVICE_PATH, + MEDIA_CDROM_DP, + DevPathSerialCdRom, + DevPathCompareDefault + }, + { + MEDIA_DEVICE_PATH, + MEDIA_VENDOR_DP, + DevPathSerialVendor, + DevPathCompareDefault + }, + { + 0, + 0, + NULL, + NULL + } +}; + +/** + Function to determine if a device path node is Hi or not. + + @param[in] DevicePathNode The node to check. + + @retval TRUE The node is Hi. + @retval FALSE The node is not Hi. +**/ +BOOLEAN +IsHIDevicePathNode ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode + ) +{ + ACPI_HID_DEVICE_PATH *Acpi; + + ASSERT(DevicePathNode != NULL); + + if (DevicePathNode->Type == HARDWARE_DEVICE_PATH) { + return TRUE; + } + + if (DevicePathNode->Type == ACPI_DEVICE_PATH) { + Acpi = (ACPI_HID_DEVICE_PATH *) DevicePathNode; + switch (EISA_ID_TO_NUM (Acpi->HID)) { + case 0x0301: + case 0x0401: + case 0x0501: + case 0x0604: + return FALSE; + } + + return TRUE; + } + + return FALSE; +} + +/** + Function to convert a standard device path structure into a Hi version. + + @param[in] DevicePath The device path to convert. + + @return the device path portion that is Hi. +**/ +EFI_DEVICE_PATH_PROTOCOL * +GetHIDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + UINTN NonHIDevicePathNodeCount; + UINTN Index; + EFI_DEV_PATH Node; + EFI_DEVICE_PATH_PROTOCOL *HIDevicePath; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; + + ASSERT(DevicePath != NULL); + + NonHIDevicePathNodeCount = 0; + + HIDevicePath = AllocateZeroPool (sizeof (EFI_DEVICE_PATH_PROTOCOL)); + SetDevicePathEndNode (HIDevicePath); + + Node.DevPath.Type = END_DEVICE_PATH_TYPE; + Node.DevPath.SubType = END_INSTANCE_DEVICE_PATH_SUBTYPE; + Node.DevPath.Length[0] = (UINT8)sizeof (EFI_DEVICE_PATH_PROTOCOL); + Node.DevPath.Length[1] = 0; + + while (!IsDevicePathEnd (DevicePath)) { + if (IsHIDevicePathNode (DevicePath)) { + for (Index = 0; Index < NonHIDevicePathNodeCount; Index++) { + TempDevicePath = AppendDevicePathNode (HIDevicePath, &Node.DevPath); + FreePool (HIDevicePath); + HIDevicePath = TempDevicePath; + } + + TempDevicePath = AppendDevicePathNode (HIDevicePath, DevicePath); + FreePool (HIDevicePath); + HIDevicePath = TempDevicePath; + } else { + NonHIDevicePathNodeCount++; + } + // + // Next device path node + // + DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) NextDevicePathNode (DevicePath); + } + + return HIDevicePath; +} + +/** + Function to walk the device path looking for a dumpable node. + + @param[in] MappingItem The Item to fill with data. + @param[in] DevicePath The path of the item to get data on. + + @return EFI_SUCCESS Always returns success. +**/ +EFI_STATUS +GetDeviceConsistMappingInfo ( + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_STATUS Status; + SERIAL_DECODE_FUNCTION SerialFun; + UINTN Index; + EFI_DEVICE_PATH_PROTOCOL *OriginalDevicePath; + + ASSERT(DevicePath != NULL); + ASSERT(MappingItem != NULL); + + SetMem (&MappingItem->Csd, sizeof (POOL_PRINT), 0); + OriginalDevicePath = DevicePath; + + while (!IsDevicePathEnd (DevicePath)) { + // + // Find the handler to dump this device path node and + // initialize with generic function in case nothing is found + // + for (SerialFun = DevPathSerialDefault, Index = 0; DevPathConsistMappingTable[Index].SerialFun != NULL; Index += 1) { + + if (DevicePathType (DevicePath) == DevPathConsistMappingTable[Index].Type && + DevicePathSubType (DevicePath) == DevPathConsistMappingTable[Index].SubType + ) { + SerialFun = DevPathConsistMappingTable[Index].SerialFun; + break; + } + } + + Status = SerialFun (DevicePath, MappingItem, OriginalDevicePath); + if (EFI_ERROR (Status)) { + SHELL_FREE_NON_NULL (MappingItem->Csd.Str); + return Status; + } + + // + // Next device path node + // + DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) NextDevicePathNode (DevicePath); + } + + return EFI_SUCCESS; +} + +/** + Function to initialize the table for creating consistent map names. + + @param[out] Table The pointer to pointer to pointer to DevicePathProtocol object. + + @retval EFI_SUCCESS The table was created successfully. +**/ +EFI_STATUS +EFIAPI +ShellCommandConsistMappingInitialize ( + OUT EFI_DEVICE_PATH_PROTOCOL ***Table + ) +{ + EFI_HANDLE *HandleBuffer; + UINTN HandleNum; + UINTN HandleLoop; + EFI_DEVICE_PATH_PROTOCOL **TempTable; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *HIDevicePath; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem; + UINTN Index; + EFI_STATUS Status; + + HandleBuffer = NULL; + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiDevicePathProtocolGuid, + NULL, + &HandleNum, + &HandleBuffer + ); + ASSERT_EFI_ERROR(Status); + + TempTable = AllocateZeroPool ((HandleNum + 1) * sizeof (EFI_DEVICE_PATH_PROTOCOL *)); + if (TempTable == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + for (HandleLoop = 0 ; HandleLoop < HandleNum ; HandleLoop++) { + DevicePath = DevicePathFromHandle (HandleBuffer[HandleLoop]); + if (DevicePath == NULL) { + continue; + } + + HIDevicePath = GetHIDevicePath (DevicePath); + if (HIDevicePath == NULL) { + continue; + } + + Status = gBS->HandleProtocol( HandleBuffer[HandleLoop], + &gEfiBlockIoProtocolGuid, + (VOID **)&BlockIo + ); + if (EFI_ERROR(Status)) { + Status = gBS->HandleProtocol( HandleBuffer[HandleLoop], + &gEfiSimpleFileSystemProtocolGuid, + (VOID **)&SimpleFileSystem + ); + if (EFI_ERROR(Status)) { + FreePool (HIDevicePath); + continue; + } + } + + for (Index = 0; TempTable[Index] != NULL; Index++) { + if (DevicePathCompare (&TempTable[Index], &HIDevicePath) == 0) { + FreePool (HIDevicePath); + break; + } + } + + if (TempTable[Index] == NULL) { + TempTable[Index] = HIDevicePath; + } + } + + for (Index = 0; TempTable[Index] != NULL; Index++); + PerformQuickSort(TempTable, Index, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare); + *Table = TempTable; + + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + + return EFI_SUCCESS; +} + +/** + Function to uninitialize the table for creating consistent map names. + + The parameter must have been received from ShellCommandConsistMappingInitialize. + + @param[out] Table The pointer to pointer to DevicePathProtocol object. + + @retval EFI_SUCCESS The table was deleted successfully. +**/ +EFI_STATUS +EFIAPI +ShellCommandConsistMappingUnInitialize ( + EFI_DEVICE_PATH_PROTOCOL **Table + ) +{ + UINTN Index; + + ASSERT(Table != NULL); + + for (Index = 0; Table[Index] != NULL; Index++) { + FreePool (Table[Index]); + } + + FreePool (Table); + return EFI_SUCCESS; +} + +/** + Create a consistent mapped name for the device specified by DevicePath + based on the Table. + + This must be called after ShellCommandConsistMappingInitialize() and + before ShellCommandConsistMappingUnInitialize() is called. + + @param[in] DevicePath The pointer to the dev path for the device. + @param[in] Table The Table of mapping information. + + @retval NULL A consistent mapped name could not be created. + @return A pointer to a string allocated from pool with the device name. +**/ +CHAR16 * +EFIAPI +ShellCommandConsistMappingGenMappingName ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_DEVICE_PATH_PROTOCOL **Table + ) +{ + EFI_STATUS Status; + POOL_PRINT Str; + DEVICE_CONSIST_MAPPING_INFO MappingInfo; + EFI_DEVICE_PATH_PROTOCOL *HIDevicePath; + UINTN Index; + + ASSERT(DevicePath != NULL); + ASSERT(Table != NULL); + + HIDevicePath = GetHIDevicePath (DevicePath); + if (HIDevicePath == NULL) { + return NULL; + } + + for (Index = 0; Table[Index] != NULL; Index++) { + if (DevicePathCompare (&Table[Index], &HIDevicePath) == 0) { + break; + } + } + + FreePool (HIDevicePath); + if (Table[Index] == NULL) { + return NULL; + } + + MappingInfo.Hi = Index; + MappingInfo.Mtd = MTDTypeUnknown; + MappingInfo.Digital = FALSE; + + Status = GetDeviceConsistMappingInfo (&MappingInfo, DevicePath); + if (EFI_ERROR (Status)) { + return NULL; + } + + SetMem (&Str, sizeof (Str), 0); + for (Index = 0; mMTDName[Index].MTDType != MTDTypeEnd; Index++) { + if (MappingInfo.Mtd == mMTDName[Index].MTDType) { + break; + } + } + + if (mMTDName[Index].MTDType != MTDTypeEnd) { + Status = CatPrint (&Str, L"%s", mMTDName[Index].Name); + } + + if (!EFI_ERROR (Status)) { + Status = CatPrint (&Str, L"%d", (UINTN) MappingInfo.Hi); + } + if (!EFI_ERROR (Status) && MappingInfo.Csd.Str != NULL) { + Status = CatPrint (&Str, L"%s", MappingInfo.Csd.Str); + FreePool (MappingInfo.Csd.Str); + } + + if (!EFI_ERROR (Status) && Str.Str != NULL) { + Status = CatPrint (&Str, L":"); + } + if (EFI_ERROR (Status)) { + SHELL_FREE_NON_NULL (Str.Str); + return NULL; + } + + return Str.Str; +} + +/** + Function to search the list of mappings for the node on the list based on the key. + + @param[in] MapKey String Key to search for on the map + + @return the node on the list. +**/ +SHELL_MAP_LIST * +EFIAPI +ShellCommandFindMapItem ( + IN CONST CHAR16 *MapKey + ) +{ + SHELL_MAP_LIST *MapListItem; + + for ( MapListItem = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link) + ; !IsNull(&gShellMapList.Link, &MapListItem->Link) + ; MapListItem = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &MapListItem->Link) + ){ + if (gUnicodeCollation->StriColl(gUnicodeCollation,MapListItem->MapName,(CHAR16*)MapKey) == 0) { + return (MapListItem); + } + } + return (NULL); +} + + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c new file mode 100644 index 00000000..2a44d836 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c @@ -0,0 +1,2228 @@ +/** @file + Provides interface to shell internal functions for shell commands. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellCommandLib.h" + +// STATIC local variables +STATIC SHELL_COMMAND_INTERNAL_LIST_ENTRY mCommandList; +STATIC SCRIPT_FILE_LIST mScriptList; +STATIC ALIAS_LIST mAliasList; +STATIC BOOLEAN mEchoState; +STATIC BOOLEAN mExitRequested; +STATIC UINT64 mExitCode; +STATIC BOOLEAN mExitScript; +STATIC CHAR16 *mProfileList; +STATIC UINTN mProfileListSize; +STATIC UINTN mFsMaxCount = 0; +STATIC UINTN mBlkMaxCount = 0; +STATIC BUFFER_LIST mFileHandleList; + +STATIC CONST CHAR8 Hex[] = { + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + 'A', + 'B', + 'C', + 'D', + 'E', + 'F' +}; + +// global variables required by library class. +EFI_UNICODE_COLLATION_PROTOCOL *gUnicodeCollation = NULL; +SHELL_MAP_LIST gShellMapList; +SHELL_MAP_LIST *gShellCurMapping = NULL; + +CONST CHAR16* SupportLevel[] = { + L"Minimal", + L"Scripting", + L"Basic", + L"Interactive" +}; + +/** + Function to make sure that the global protocol pointers are valid. + must be called after constructor before accessing the pointers. +**/ +EFI_STATUS +EFIAPI +CommandInit( + VOID + ) +{ + UINTN NumHandles; + EFI_HANDLE *Handles; + EFI_UNICODE_COLLATION_PROTOCOL *Uc; + CHAR8 *BestLanguage; + UINTN Index; + EFI_STATUS Status; + CHAR8 *PlatformLang; + + if (gUnicodeCollation == NULL) { + + GetEfiGlobalVariable2 (EFI_PLATFORM_LANG_VARIABLE_NAME, (VOID**)&PlatformLang, NULL); + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiUnicodeCollation2ProtocolGuid, + NULL, + &NumHandles, + &Handles + ); + if (EFI_ERROR (Status)) { + NumHandles = 0; + Handles = NULL; + } + for (Index = 0; Index < NumHandles; Index++) { + // + // Open Unicode Collation Protocol + // + Status = gBS->OpenProtocol ( + Handles[Index], + &gEfiUnicodeCollation2ProtocolGuid, + (VOID **) &Uc, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + continue; + } + + // + // Without clue provided use the first Unicode Collation2 protocol. + // This may happen when PlatformLang is NULL or when no installed Unicode + // Collation2 protocol instance supports PlatformLang. + // + if (gUnicodeCollation == NULL) { + gUnicodeCollation = Uc; + } + if (PlatformLang == NULL) { + break; + } + + // + // Find the best matching matching language from the supported languages + // of Unicode Collation2 protocol. + // + BestLanguage = GetBestLanguage ( + Uc->SupportedLanguages, + FALSE, + PlatformLang, + NULL + ); + if (BestLanguage != NULL) { + FreePool (BestLanguage); + gUnicodeCollation = Uc; + break; + } + } + if (Handles != NULL) { + FreePool (Handles); + } + if (PlatformLang != NULL) { + FreePool (PlatformLang); + } + } + + return (gUnicodeCollation == NULL) ? EFI_UNSUPPORTED : EFI_SUCCESS; +} + +/** + Constructor for the Shell Command library. + + Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell. + + @param ImageHandle the image handle of the process + @param SystemTable the EFI System Table pointer + + @retval EFI_SUCCESS the initialization was complete sucessfully +**/ +RETURN_STATUS +EFIAPI +ShellCommandLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + InitializeListHead(&gShellMapList.Link); + InitializeListHead(&mCommandList.Link); + InitializeListHead(&mAliasList.Link); + InitializeListHead(&mScriptList.Link); + InitializeListHead(&mFileHandleList.Link); + mEchoState = TRUE; + + mExitRequested = FALSE; + mExitScript = FALSE; + mProfileListSize = 0; + mProfileList = NULL; + + Status = CommandInit (); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + return (RETURN_SUCCESS); +} + +/** + Frees list of file handles. + + @param[in] List The list to free. +**/ +VOID +FreeFileHandleList ( + IN BUFFER_LIST *List + ) +{ + BUFFER_LIST *BufferListEntry; + + if (List == NULL){ + return; + } + // + // enumerate through the buffer list and free all memory + // + for ( BufferListEntry = ( BUFFER_LIST *)GetFirstNode(&List->Link) + ; !IsListEmpty (&List->Link) + ; BufferListEntry = (BUFFER_LIST *)GetFirstNode(&List->Link) + ){ + RemoveEntryList(&BufferListEntry->Link); + ASSERT(BufferListEntry->Buffer != NULL); + SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE*)(BufferListEntry->Buffer))->Path); + SHELL_FREE_NON_NULL(BufferListEntry->Buffer); + SHELL_FREE_NON_NULL(BufferListEntry); + } +} + +/** + Destructor for the library. free any resources. + + @param ImageHandle the image handle of the process + @param SystemTable the EFI System Table pointer + + @retval RETURN_SUCCESS this function always returns success +**/ +RETURN_STATUS +EFIAPI +ShellCommandLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node; + ALIAS_LIST *Node2; + SCRIPT_FILE_LIST *Node3; + SHELL_MAP_LIST *MapNode; + // + // enumerate throught the list and free all the memory + // + while (!IsListEmpty (&mCommandList.Link)) { + Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link); + RemoveEntryList(&Node->Link); + SHELL_FREE_NON_NULL(Node->CommandString); + FreePool(Node); + DEBUG_CODE(Node = NULL;); + } + + // + // enumerate through the alias list and free all memory + // + while (!IsListEmpty (&mAliasList.Link)) { + Node2 = (ALIAS_LIST *)GetFirstNode(&mAliasList.Link); + RemoveEntryList(&Node2->Link); + SHELL_FREE_NON_NULL(Node2->CommandString); + SHELL_FREE_NON_NULL(Node2->Alias); + SHELL_FREE_NON_NULL(Node2); + DEBUG_CODE(Node2 = NULL;); + } + + // + // enumerate throught the list and free all the memory + // + while (!IsListEmpty (&mScriptList.Link)) { + Node3 = (SCRIPT_FILE_LIST *)GetFirstNode(&mScriptList.Link); + RemoveEntryList(&Node3->Link); + DeleteScriptFileStruct(Node3->Data); + FreePool(Node3); + } + + // + // enumerate throught the mappings list and free all the memory + // + if (!IsListEmpty(&gShellMapList.Link)) { + for (MapNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link) + ; !IsListEmpty (&gShellMapList.Link) + ; MapNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link) + ){ + ASSERT(MapNode != NULL); + RemoveEntryList(&MapNode->Link); + SHELL_FREE_NON_NULL(MapNode->DevicePath); + SHELL_FREE_NON_NULL(MapNode->MapName); + SHELL_FREE_NON_NULL(MapNode->CurrentDirectoryPath); + FreePool(MapNode); + } + } + if (!IsListEmpty(&mFileHandleList.Link)){ + FreeFileHandleList(&mFileHandleList); + } + + if (mProfileList != NULL) { + FreePool(mProfileList); + } + + gUnicodeCollation = NULL; + gShellCurMapping = NULL; + + return (RETURN_SUCCESS); +} + +/** + Find a dynamic command protocol instance given a command name string. + + @param CommandString the command name string + + @return instance the command protocol instance, if dynamic command instance found + @retval NULL no dynamic command protocol instance found for name +**/ +CONST EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL * +ShellCommandFindDynamicCommand ( + IN CONST CHAR16 *CommandString + ) +{ + EFI_STATUS Status; + EFI_HANDLE *CommandHandleList; + EFI_HANDLE *NextCommand; + EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand; + + CommandHandleList = GetHandleListByProtocol(&gEfiShellDynamicCommandProtocolGuid); + if (CommandHandleList == NULL) { + // + // not found or out of resources + // + return NULL; + } + + for (NextCommand = CommandHandleList; *NextCommand != NULL; NextCommand++) { + Status = gBS->HandleProtocol( + *NextCommand, + &gEfiShellDynamicCommandProtocolGuid, + (VOID **)&DynamicCommand + ); + + if (EFI_ERROR(Status)) { + continue; + } + + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)CommandString, + (CHAR16*)DynamicCommand->CommandName) == 0 + ){ + FreePool(CommandHandleList); + return (DynamicCommand); + } + } + + FreePool(CommandHandleList); + return (NULL); +} + +/** + Checks if a command exists as a dynamic command protocol instance + + @param[in] CommandString The command string to check for on the list. +**/ +BOOLEAN +ShellCommandDynamicCommandExists ( + IN CONST CHAR16 *CommandString + ) +{ + return (BOOLEAN) ((ShellCommandFindDynamicCommand(CommandString) != NULL)); +} + +/** + Checks if a command is already on the internal command list. + + @param[in] CommandString The command string to check for on the list. +**/ +BOOLEAN +ShellCommandIsCommandOnInternalList( + IN CONST CHAR16 *CommandString + ) +{ + SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node; + + // + // assert for NULL parameter + // + ASSERT(CommandString != NULL); + + // + // check for the command + // + for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link) + ; !IsNull(&mCommandList.Link, &Node->Link) + ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link) + ){ + ASSERT(Node->CommandString != NULL); + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)CommandString, + Node->CommandString) == 0 + ){ + return (TRUE); + } + } + return (FALSE); +} + +/** + Checks if a command exists, either internally or through the dynamic command protocol. + + @param[in] CommandString The command string to check for on the list. +**/ +BOOLEAN +EFIAPI +ShellCommandIsCommandOnList( + IN CONST CHAR16 *CommandString + ) +{ + if (ShellCommandIsCommandOnInternalList(CommandString)) { + return TRUE; + } + + return ShellCommandDynamicCommandExists(CommandString); +} + +/** + Get the help text for a dynamic command. + + @param[in] CommandString The command name. + + @retval NULL No help text was found. + @return String of help text. Caller required to free. +**/ +CHAR16* +ShellCommandGetDynamicCommandHelp( + IN CONST CHAR16 *CommandString + ) +{ + EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand; + + DynamicCommand = (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *)ShellCommandFindDynamicCommand(CommandString); + if (DynamicCommand == NULL) { + return (NULL); + } + + // + // TODO: how to get proper language? + // + return DynamicCommand->GetHelp(DynamicCommand, "en"); +} + +/** + Get the help text for an internal command. + + @param[in] CommandString The command name. + + @retval NULL No help text was found. + @return String of help text. Caller reuiqred to free. +**/ +CHAR16* +ShellCommandGetInternalCommandHelp( + IN CONST CHAR16 *CommandString + ) +{ + SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node; + + // + // assert for NULL parameter + // + ASSERT(CommandString != NULL); + + // + // check for the command + // + for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link) + ; !IsNull(&mCommandList.Link, &Node->Link) + ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link) + ){ + ASSERT(Node->CommandString != NULL); + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)CommandString, + Node->CommandString) == 0 + ){ + return (HiiGetString(Node->HiiHandle, Node->ManFormatHelp, NULL)); + } + } + return (NULL); +} + +/** + Get the help text for a command. + + @param[in] CommandString The command name. + + @retval NULL No help text was found. + @return String of help text.Caller reuiqred to free. +**/ +CHAR16* +EFIAPI +ShellCommandGetCommandHelp ( + IN CONST CHAR16 *CommandString + ) +{ + CHAR16 *HelpStr; + HelpStr = ShellCommandGetInternalCommandHelp(CommandString); + + if (HelpStr == NULL) { + HelpStr = ShellCommandGetDynamicCommandHelp(CommandString); + } + + return HelpStr; +} + + +/** + Registers handlers of type SHELL_RUN_COMMAND and + SHELL_GET_MAN_FILENAME for each shell command. + + If the ShellSupportLevel is greater than the value of the + PcdShellSupportLevel then return RETURN_UNSUPPORTED. + + Registers the handlers specified by GetHelpInfoHandler and CommandHandler + with the command specified by CommandString. If the command named by + CommandString has already been registered, then return + RETURN_ALREADY_STARTED. + + If there are not enough resources available to register the handlers then + RETURN_OUT_OF_RESOURCES is returned. + + If CommandString is NULL, then ASSERT(). + If GetHelpInfoHandler is NULL, then ASSERT(). + If CommandHandler is NULL, then ASSERT(). + If ProfileName is NULL, then ASSERT(). + + @param[in] CommandString Pointer to the command name. This is the + name to look for on the command line in + the shell. + @param[in] CommandHandler Pointer to a function that runs the + specified command. + @param[in] GetManFileName Pointer to a function that provides man + filename. + @param[in] ShellMinSupportLevel minimum Shell Support Level which has this + function. + @param[in] ProfileName profile name to require for support of this + function. + @param[in] CanAffectLE indicates whether this command's return value + can change the LASTERROR environment variable. + @param[in] HiiHandle Handle of this command's HII entry. + @param[in] ManFormatHelp HII locator for the help text. + + @retval RETURN_SUCCESS The handlers were registered. + @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to + register the shell command. + @retval RETURN_UNSUPPORTED the ShellMinSupportLevel was higher than the + currently allowed support level. + @retval RETURN_ALREADY_STARTED The CommandString represents a command that + is already registered. Only 1 handler set for + a given command is allowed. + @sa SHELL_GET_MAN_FILENAME + @sa SHELL_RUN_COMMAND +**/ +RETURN_STATUS +EFIAPI +ShellCommandRegisterCommandName ( + IN CONST CHAR16 *CommandString, + IN SHELL_RUN_COMMAND CommandHandler, + IN SHELL_GET_MAN_FILENAME GetManFileName, + IN UINT32 ShellMinSupportLevel, + IN CONST CHAR16 *ProfileName, + IN CONST BOOLEAN CanAffectLE, + IN CONST EFI_HII_HANDLE HiiHandle, + IN CONST EFI_STRING_ID ManFormatHelp + ) +{ + SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node; + SHELL_COMMAND_INTERNAL_LIST_ENTRY *Command; + SHELL_COMMAND_INTERNAL_LIST_ENTRY *PrevCommand; + INTN LexicalMatchValue; + + // + // Initialize local variables. + // + Command = NULL; + PrevCommand = NULL; + LexicalMatchValue = 0; + + // + // ASSERTs for NULL parameters + // + ASSERT(CommandString != NULL); + ASSERT(GetManFileName != NULL); + ASSERT(CommandHandler != NULL); + ASSERT(ProfileName != NULL); + + // + // check for shell support level + // + if (PcdGet8(PcdShellSupportLevel) < ShellMinSupportLevel) { + return (RETURN_UNSUPPORTED); + } + + // + // check for already on the list + // + if (ShellCommandIsCommandOnList(CommandString)) { + return (RETURN_ALREADY_STARTED); + } + + // + // allocate memory for new struct + // + Node = AllocateZeroPool(sizeof(SHELL_COMMAND_INTERNAL_LIST_ENTRY)); + if (Node == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + Node->CommandString = AllocateCopyPool(StrSize(CommandString), CommandString); + if (Node->CommandString == NULL) { + FreePool (Node); + return RETURN_OUT_OF_RESOURCES; + } + + Node->GetManFileName = GetManFileName; + Node->CommandHandler = CommandHandler; + Node->LastError = CanAffectLE; + Node->HiiHandle = HiiHandle; + Node->ManFormatHelp = ManFormatHelp; + + if ( StrLen(ProfileName)>0 + && ((mProfileList != NULL + && StrStr(mProfileList, ProfileName) == NULL) || mProfileList == NULL) + ){ + ASSERT((mProfileList == NULL && mProfileListSize == 0) || (mProfileList != NULL)); + if (mProfileList == NULL) { + // + // If this is the first make a leading ';' + // + StrnCatGrow(&mProfileList, &mProfileListSize, L";", 0); + } + StrnCatGrow(&mProfileList, &mProfileListSize, ProfileName, 0); + StrnCatGrow(&mProfileList, &mProfileListSize, L";", 0); + } + + // + // Insert a new entry on top of the list + // + InsertHeadList (&mCommandList.Link, &Node->Link); + + // + // Move a new registered command to its sorted ordered location in the list + // + for (Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link), + PrevCommand = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link) + ; !IsNull (&mCommandList.Link, &Command->Link) + ; Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode (&mCommandList.Link, &Command->Link)) { + + // + // Get Lexical Comparison Value between PrevCommand and Command list entry + // + LexicalMatchValue = gUnicodeCollation->StriColl ( + gUnicodeCollation, + PrevCommand->CommandString, + Command->CommandString + ); + + // + // Swap PrevCommand and Command list entry if PrevCommand list entry + // is alphabetically greater than Command list entry + // + if (LexicalMatchValue > 0){ + Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *) SwapListEntries (&PrevCommand->Link, &Command->Link); + } else if (LexicalMatchValue < 0) { + // + // PrevCommand entry is lexically lower than Command entry + // + break; + } + } + + return (RETURN_SUCCESS); +} + +/** + Function to get the current Profile string. + + @retval NULL There are no installed profiles. + @return A semi-colon delimited list of profiles. +**/ +CONST CHAR16 * +EFIAPI +ShellCommandGetProfileList ( + VOID + ) +{ + return (mProfileList); +} + +/** + Checks if a command string has been registered for CommandString and if so it runs + the previously registered handler for that command with the command line. + + If CommandString is NULL, then ASSERT(). + + If Sections is specified, then each section name listed will be compared in a casesensitive + manner, to the section names described in Appendix B UEFI Shell 2.0 spec. If the section exists, + it will be appended to the returned help text. If the section does not exist, no + information will be returned. If Sections is NULL, then all help text information + available will be returned. + + @param[in] CommandString Pointer to the command name. This is the name + found on the command line in the shell. + @param[in, out] RetVal Pointer to the return vaule from the command handler. + + @param[in, out] CanAffectLE indicates whether this command's return value + needs to be placed into LASTERROR environment variable. + + @retval RETURN_SUCCESS The handler was run. + @retval RETURN_NOT_FOUND The CommandString did not match a registered + command name. + @sa SHELL_RUN_COMMAND +**/ +RETURN_STATUS +EFIAPI +ShellCommandRunCommandHandler ( + IN CONST CHAR16 *CommandString, + IN OUT SHELL_STATUS *RetVal, + IN OUT BOOLEAN *CanAffectLE OPTIONAL + ) +{ + SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node; + EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand; + + // + // assert for NULL parameters + // + ASSERT(CommandString != NULL); + + // + // check for the command + // + for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link) + ; !IsNull(&mCommandList.Link, &Node->Link) + ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link) + ){ + ASSERT(Node->CommandString != NULL); + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)CommandString, + Node->CommandString) == 0 + ){ + if (CanAffectLE != NULL) { + *CanAffectLE = Node->LastError; + } + if (RetVal != NULL) { + *RetVal = Node->CommandHandler(NULL, gST); + } else { + Node->CommandHandler(NULL, gST); + } + return (RETURN_SUCCESS); + } + } + + // + // An internal command was not found, try to find a dynamic command + // + DynamicCommand = (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *)ShellCommandFindDynamicCommand(CommandString); + if (DynamicCommand != NULL) { + if (RetVal != NULL) { + *RetVal = DynamicCommand->Handler(DynamicCommand, gST, gEfiShellParametersProtocol, gEfiShellProtocol); + } else { + DynamicCommand->Handler(DynamicCommand, gST, gEfiShellParametersProtocol, gEfiShellProtocol); + } + return (RETURN_SUCCESS); + } + + return (RETURN_NOT_FOUND); +} + +/** + Checks if a command string has been registered for CommandString and if so it + returns the MAN filename specified for that command. + + If CommandString is NULL, then ASSERT(). + + @param[in] CommandString Pointer to the command name. This is the name + found on the command line in the shell.\ + + @retval NULL the commandString was not a registered command. + @return other the name of the MAN file. + @sa SHELL_GET_MAN_FILENAME +**/ +CONST CHAR16* +EFIAPI +ShellCommandGetManFileNameHandler ( + IN CONST CHAR16 *CommandString + ) +{ + SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node; + + // + // assert for NULL parameters + // + ASSERT(CommandString != NULL); + + // + // check for the command + // + for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link) + ; !IsNull(&mCommandList.Link, &Node->Link) + ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link) + ){ + ASSERT(Node->CommandString != NULL); + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)CommandString, + Node->CommandString) == 0 + ){ + return (Node->GetManFileName()); + } + } + return (NULL); +} + +/** + Get the list of all available shell internal commands. This is a linked list + (via LIST_ENTRY structure). enumerate through it using the BaseLib linked + list functions. do not modify the values. + + @param[in] Sort TRUE to alphabetically sort the values first. FALSE otherwise. + + @return a Linked list of all available shell commands. +**/ +CONST COMMAND_LIST* +EFIAPI +ShellCommandGetCommandList ( + IN CONST BOOLEAN Sort + ) +{ +// if (!Sort) { +// return ((COMMAND_LIST*)(&mCommandList)); +// } + return ((COMMAND_LIST*)(&mCommandList)); +} + +/** + Registers aliases to be set as part of the initialization of the shell application. + + If Command is NULL, then ASSERT(). + If Alias is NULL, then ASSERT(). + + @param[in] Command Pointer to the Command + @param[in] Alias Pointer to Alias + + @retval RETURN_SUCCESS The handlers were registered. + @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to + register the shell command. +**/ +RETURN_STATUS +EFIAPI +ShellCommandRegisterAlias ( + IN CONST CHAR16 *Command, + IN CONST CHAR16 *Alias + ) +{ + ALIAS_LIST *Node; + ALIAS_LIST *CommandAlias; + ALIAS_LIST *PrevCommandAlias; + INTN LexicalMatchValue; + + // + // Asserts for NULL + // + ASSERT(Command != NULL); + ASSERT(Alias != NULL); + + // + // allocate memory for new struct + // + Node = AllocateZeroPool(sizeof(ALIAS_LIST)); + if (Node == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + Node->CommandString = AllocateCopyPool(StrSize(Command), Command); + if (Node->CommandString == NULL) { + FreePool (Node); + return RETURN_OUT_OF_RESOURCES; + } + Node->Alias = AllocateCopyPool(StrSize(Alias), Alias); + if (Node->Alias == NULL) { + FreePool (Node->CommandString); + FreePool (Node); + return RETURN_OUT_OF_RESOURCES; + } + + InsertHeadList (&mAliasList.Link, &Node->Link); + + // + // Move a new pre-defined registered alias to its sorted ordered location in the list + // + for ( CommandAlias = (ALIAS_LIST *)GetFirstNode (&mAliasList.Link), + PrevCommandAlias = (ALIAS_LIST *)GetFirstNode (&mAliasList.Link) + ; !IsNull (&mAliasList.Link, &CommandAlias->Link) + ; CommandAlias = (ALIAS_LIST *) GetNextNode (&mAliasList.Link, &CommandAlias->Link) ) { + // + // Get Lexical comparison value between PrevCommandAlias and CommandAlias List Entry + // + LexicalMatchValue = gUnicodeCollation->StriColl ( + gUnicodeCollation, + PrevCommandAlias->Alias, + CommandAlias->Alias + ); + + // + // Swap PrevCommandAlias and CommandAlias list entry if PrevCommandAlias list entry + // is alphabetically greater than CommandAlias list entry + // + if (LexicalMatchValue > 0) { + CommandAlias = (ALIAS_LIST *) SwapListEntries (&PrevCommandAlias->Link, &CommandAlias->Link); + } else if (LexicalMatchValue < 0) { + // + // PrevCommandAlias entry is lexically lower than CommandAlias entry + // + break; + } + } + + return (RETURN_SUCCESS); +} + +/** + Get the list of all shell alias commands. This is a linked list + (via LIST_ENTRY structure). enumerate through it using the BaseLib linked + list functions. do not modify the values. + + @return a Linked list of all requested shell alias'. +**/ +CONST ALIAS_LIST* +EFIAPI +ShellCommandGetInitAliasList ( + VOID + ) +{ + return (&mAliasList); +} + +/** + Determine if a given alias is on the list of built in alias'. + + @param[in] Alias The alias to test for + + @retval TRUE The alias is a built in alias + @retval FALSE The alias is not a built in alias +**/ +BOOLEAN +EFIAPI +ShellCommandIsOnAliasList( + IN CONST CHAR16 *Alias + ) +{ + ALIAS_LIST *Node; + + // + // assert for NULL parameter + // + ASSERT(Alias != NULL); + + // + // check for the Alias + // + for ( Node = (ALIAS_LIST *)GetFirstNode(&mAliasList.Link) + ; !IsNull(&mAliasList.Link, &Node->Link) + ; Node = (ALIAS_LIST *)GetNextNode(&mAliasList.Link, &Node->Link) + ){ + ASSERT(Node->CommandString != NULL); + ASSERT(Node->Alias != NULL); + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)Alias, + Node->CommandString) == 0 + ){ + return (TRUE); + } + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)Alias, + Node->Alias) == 0 + ){ + return (TRUE); + } + } + return (FALSE); +} + +/** + Function to determine current state of ECHO. Echo determines if lines from scripts + and ECHO commands are enabled. + + @retval TRUE Echo is currently enabled + @retval FALSE Echo is currently disabled +**/ +BOOLEAN +EFIAPI +ShellCommandGetEchoState( + VOID + ) +{ + return (mEchoState); +} + +/** + Function to set current state of ECHO. Echo determines if lines from scripts + and ECHO commands are enabled. + + If State is TRUE, Echo will be enabled. + If State is FALSE, Echo will be disabled. + + @param[in] State How to set echo. +**/ +VOID +EFIAPI +ShellCommandSetEchoState( + IN BOOLEAN State + ) +{ + mEchoState = State; +} + +/** + Indicate that the current shell or script should exit. + + @param[in] ScriptOnly TRUE if exiting a script; FALSE otherwise. + @param[in] ErrorCode The 64 bit error code to return. +**/ +VOID +EFIAPI +ShellCommandRegisterExit ( + IN BOOLEAN ScriptOnly, + IN CONST UINT64 ErrorCode + ) +{ + mExitRequested = (BOOLEAN)(!mExitRequested); + if (mExitRequested) { + mExitScript = ScriptOnly; + } else { + mExitScript = FALSE; + } + mExitCode = ErrorCode; +} + +/** + Retrieve the Exit indicator. + + @retval TRUE Exit was indicated. + @retval FALSE Exis was not indicated. +**/ +BOOLEAN +EFIAPI +ShellCommandGetExit ( + VOID + ) +{ + return (mExitRequested); +} + +/** + Retrieve the Exit code. + + If ShellCommandGetExit returns FALSE than the return from this is undefined. + + @return the value passed into RegisterExit. +**/ +UINT64 +EFIAPI +ShellCommandGetExitCode ( + VOID + ) +{ + return (mExitCode); +} +/** + Retrieve the Exit script indicator. + + If ShellCommandGetExit returns FALSE than the return from this is undefined. + + @retval TRUE ScriptOnly was indicated. + @retval FALSE ScriptOnly was not indicated. +**/ +BOOLEAN +EFIAPI +ShellCommandGetScriptExit ( + VOID + ) +{ + return (mExitScript); +} + +/** + Function to cleanup all memory from a SCRIPT_FILE structure. + + @param[in] Script The pointer to the structure to cleanup. +**/ +VOID +EFIAPI +DeleteScriptFileStruct ( + IN SCRIPT_FILE *Script + ) +{ + UINT8 LoopVar; + + if (Script == NULL) { + return; + } + + for (LoopVar = 0 ; LoopVar < Script->Argc ; LoopVar++) { + SHELL_FREE_NON_NULL(Script->Argv[LoopVar]); + } + if (Script->Argv != NULL) { + SHELL_FREE_NON_NULL(Script->Argv); + } + Script->CurrentCommand = NULL; + while (!IsListEmpty (&Script->CommandList)) { + Script->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetFirstNode(&Script->CommandList); + if (Script->CurrentCommand != NULL) { + RemoveEntryList(&Script->CurrentCommand->Link); + if (Script->CurrentCommand->Cl != NULL) { + SHELL_FREE_NON_NULL(Script->CurrentCommand->Cl); + } + if (Script->CurrentCommand->Data != NULL) { + SHELL_FREE_NON_NULL(Script->CurrentCommand->Data); + } + SHELL_FREE_NON_NULL(Script->CurrentCommand); + } + } + SHELL_FREE_NON_NULL(Script->ScriptName); + SHELL_FREE_NON_NULL(Script); +} + +/** + Function to return a pointer to the currently running script file object. + + @retval NULL A script file is not currently running. + @return A pointer to the current script file object. +**/ +SCRIPT_FILE* +EFIAPI +ShellCommandGetCurrentScriptFile ( + VOID + ) +{ + SCRIPT_FILE_LIST *List; + if (IsListEmpty (&mScriptList.Link)) { + return (NULL); + } + List = ((SCRIPT_FILE_LIST*)GetFirstNode(&mScriptList.Link)); + return (List->Data); +} + +/** + Function to set a new script as the currently running one. + + This function will correctly stack and unstack nested scripts. + + @param[in] Script Pointer to new script information structure. if NULL + will remove and de-allocate the top-most Script structure. + + @return A pointer to the current running script file after this + change. NULL if removing the final script. +**/ +SCRIPT_FILE* +EFIAPI +ShellCommandSetNewScript ( + IN SCRIPT_FILE *Script OPTIONAL + ) +{ + SCRIPT_FILE_LIST *Node; + if (Script == NULL) { + if (IsListEmpty (&mScriptList.Link)) { + return (NULL); + } + Node = (SCRIPT_FILE_LIST *)GetFirstNode(&mScriptList.Link); + RemoveEntryList(&Node->Link); + DeleteScriptFileStruct(Node->Data); + FreePool(Node); + } else { + Node = AllocateZeroPool(sizeof(SCRIPT_FILE_LIST)); + if (Node == NULL) { + return (NULL); + } + Node->Data = Script; + InsertHeadList(&mScriptList.Link, &Node->Link); + } + return (ShellCommandGetCurrentScriptFile()); +} + +/** + Function to generate the next default mapping name. + + If the return value is not NULL then it must be callee freed. + + @param Type What kind of mapping name to make. + + @retval NULL a memory allocation failed. + @return a new map name string +**/ +CHAR16* +EFIAPI +ShellCommandCreateNewMappingName( + IN CONST SHELL_MAPPING_TYPE Type + ) +{ + CHAR16 *String; + ASSERT(Type < MappingTypeMax); + + String = NULL; + + String = AllocateZeroPool(PcdGet8(PcdShellMapNameLength) * sizeof(String[0])); + UnicodeSPrint( + String, + PcdGet8(PcdShellMapNameLength) * sizeof(String[0]), + Type == MappingTypeFileSystem?L"FS%d:":L"BLK%d:", + Type == MappingTypeFileSystem?mFsMaxCount++:mBlkMaxCount++); + + return (String); +} + +/** + Function to add a map node to the list of map items and update the "path" environment variable (optionally). + + If Path is TRUE (during initialization only), the path environment variable will also be updated to include + default paths on the new map name... + + Path should be FALSE when this function is called from the protocol SetMap function. + + @param[in] Name The human readable mapped name. + @param[in] DevicePath The Device Path for this map. + @param[in] Flags The Flags attribute for this map item. + @param[in] Path TRUE to update path, FALSE to skip this step (should only be TRUE during initialization). + + @retval EFI_SUCCESS The addition was sucessful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_INVALID_PARAMETER A parameter was invalid. +**/ +EFI_STATUS +EFIAPI +ShellCommandAddMapItemAndUpdatePath( + IN CONST CHAR16 *Name, + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN CONST UINT64 Flags, + IN CONST BOOLEAN Path + ) +{ + EFI_STATUS Status; + SHELL_MAP_LIST *MapListNode; + CONST CHAR16 *OriginalPath; + CHAR16 *NewPath; + UINTN NewPathSize; + + NewPathSize = 0; + NewPath = NULL; + OriginalPath = NULL; + Status = EFI_SUCCESS; + + MapListNode = AllocateZeroPool(sizeof(SHELL_MAP_LIST)); + if (MapListNode == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + MapListNode->Flags = Flags; + MapListNode->MapName = AllocateCopyPool(StrSize(Name), Name); + MapListNode->DevicePath = DuplicateDevicePath(DevicePath); + if ((MapListNode->MapName == NULL) || (MapListNode->DevicePath == NULL)){ + Status = EFI_OUT_OF_RESOURCES; + } else { + InsertTailList(&gShellMapList.Link, &MapListNode->Link); + } + } + if (EFI_ERROR(Status)) { + if (MapListNode != NULL) { + if (MapListNode->DevicePath != NULL) { + FreePool(MapListNode->DevicePath); + } + if (MapListNode->MapName != NULL) { + FreePool(MapListNode->MapName); + } + FreePool(MapListNode); + } + } else if (Path) { + // + // Since there was no error and Path was TRUE + // Now add the correct path for that mapping + // + OriginalPath = gEfiShellProtocol->GetEnv(L"path"); + ASSERT((NewPath == NULL && NewPathSize == 0) || (NewPath != NULL)); + if (OriginalPath != NULL) { + StrnCatGrow(&NewPath, &NewPathSize, OriginalPath, 0); + StrnCatGrow(&NewPath, &NewPathSize, L";", 0); + } + StrnCatGrow(&NewPath, &NewPathSize, Name, 0); + StrnCatGrow(&NewPath, &NewPathSize, L"\\efi\\tools\\;", 0); + StrnCatGrow(&NewPath, &NewPathSize, Name, 0); + StrnCatGrow(&NewPath, &NewPathSize, L"\\efi\\boot\\;", 0); + StrnCatGrow(&NewPath, &NewPathSize, Name, 0); + StrnCatGrow(&NewPath, &NewPathSize, L"\\", 0); + + Status = gEfiShellProtocol->SetEnv(L"path", NewPath, TRUE); + ASSERT_EFI_ERROR(Status); + FreePool(NewPath); + } + return (Status); +} + +/** + Creates the default map names for each device path in the system with + a protocol depending on the Type. + + Creates the consistent map names for each device path in the system with + a protocol depending on the Type. + + Note: This will reset all mappings in the system("map -r"). + + Also sets up the default path environment variable if Type is FileSystem. + + @retval EFI_SUCCESS All map names were created sucessfully. + @retval EFI_NOT_FOUND No protocols were found in the system. + @return Error returned from gBS->LocateHandle(). + + @sa LocateHandle +**/ +EFI_STATUS +EFIAPI +ShellCommandCreateInitialMappingsAndPaths( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleList; + UINTN Count; + EFI_DEVICE_PATH_PROTOCOL **DevicePathList; + CHAR16 *NewDefaultName; + CHAR16 *NewConsistName; + EFI_DEVICE_PATH_PROTOCOL **ConsistMappingTable; + SHELL_MAP_LIST *MapListNode; + CONST CHAR16 *CurDir; + CHAR16 *SplitCurDir; + CHAR16 *MapName; + SHELL_MAP_LIST *MapListItem; + + SplitCurDir = NULL; + MapName = NULL; + MapListItem = NULL; + HandleList = NULL; + + // + // Reset the static members back to zero + // + mFsMaxCount = 0; + mBlkMaxCount = 0; + + gEfiShellProtocol->SetEnv(L"path", L"", TRUE); + + // + // First empty out the existing list. + // + if (!IsListEmpty(&gShellMapList.Link)) { + for ( MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link) + ; !IsListEmpty(&gShellMapList.Link) + ; MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link) + ){ + RemoveEntryList(&MapListNode->Link); + SHELL_FREE_NON_NULL(MapListNode->DevicePath); + SHELL_FREE_NON_NULL(MapListNode->MapName); + SHELL_FREE_NON_NULL(MapListNode->CurrentDirectoryPath); + FreePool(MapListNode); + } // for loop + } + + // + // Find each handle with Simple File System + // + HandleList = GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid); + if (HandleList != NULL) { + // + // Do a count of the handles + // + for (Count = 0 ; HandleList[Count] != NULL ; Count++); + + // + // Get all Device Paths + // + DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count); + if (DevicePathList == NULL) { + SHELL_FREE_NON_NULL (HandleList); + return EFI_OUT_OF_RESOURCES; + } + + for (Count = 0 ; HandleList[Count] != NULL ; Count++) { + DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]); + } + + // + // Sort all DevicePaths + // + PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare); + + ShellCommandConsistMappingInitialize(&ConsistMappingTable); + // + // Assign new Mappings to all... + // + for (Count = 0 ; HandleList[Count] != NULL ; Count++) { + // + // Get default name first + // + NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeFileSystem); + ASSERT(NewDefaultName != NULL); + Status = ShellCommandAddMapItemAndUpdatePath(NewDefaultName, DevicePathList[Count], 0, TRUE); + ASSERT_EFI_ERROR(Status); + FreePool(NewDefaultName); + + // + // Now do consistent name + // + NewConsistName = ShellCommandConsistMappingGenMappingName(DevicePathList[Count], ConsistMappingTable); + if (NewConsistName != NULL) { + Status = ShellCommandAddMapItemAndUpdatePath(NewConsistName, DevicePathList[Count], 0, FALSE); + ASSERT_EFI_ERROR(Status); + FreePool(NewConsistName); + } + } + + ShellCommandConsistMappingUnInitialize(ConsistMappingTable); + + SHELL_FREE_NON_NULL(HandleList); + SHELL_FREE_NON_NULL(DevicePathList); + + HandleList = NULL; + + // + //gShellCurMapping point to node of current file system in the gShellMapList. When reset all mappings, + //all nodes in the gShellMapList will be free. Then gShellCurMapping will be a dangling pointer, So, + //after created new mappings, we should reset the gShellCurMapping pointer back to node of current file system. + // + if (gShellCurMapping != NULL) { + gShellCurMapping = NULL; + CurDir = gEfiShellProtocol->GetEnv(L"cwd"); + if (CurDir != NULL) { + MapName = AllocateCopyPool (StrSize(CurDir), CurDir); + if (MapName == NULL) { + return EFI_OUT_OF_RESOURCES; + } + SplitCurDir = StrStr (MapName, L":"); + if (SplitCurDir == NULL) { + SHELL_FREE_NON_NULL (MapName); + return EFI_UNSUPPORTED; + } + *(SplitCurDir + 1) = CHAR_NULL; + MapListItem = ShellCommandFindMapItem (MapName); + if (MapListItem != NULL) { + gShellCurMapping = MapListItem; + } + SHELL_FREE_NON_NULL (MapName); + } + } + } else { + Count = (UINTN)-1; + } + + // + // Find each handle with Block Io + // + HandleList = GetHandleListByProtocol(&gEfiBlockIoProtocolGuid); + if (HandleList != NULL) { + for (Count = 0 ; HandleList[Count] != NULL ; Count++); + + // + // Get all Device Paths + // + DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count); + if (DevicePathList == NULL) { + SHELL_FREE_NON_NULL (HandleList); + return EFI_OUT_OF_RESOURCES; + } + + for (Count = 0 ; HandleList[Count] != NULL ; Count++) { + DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]); + } + + // + // Sort all DevicePaths + // + PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare); + + // + // Assign new Mappings to all... + // + for (Count = 0 ; HandleList[Count] != NULL ; Count++) { + // + // Get default name first + // + NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeBlockIo); + ASSERT(NewDefaultName != NULL); + Status = ShellCommandAddMapItemAndUpdatePath(NewDefaultName, DevicePathList[Count], 0, FALSE); + ASSERT_EFI_ERROR(Status); + FreePool(NewDefaultName); + } + + SHELL_FREE_NON_NULL(HandleList); + SHELL_FREE_NON_NULL(DevicePathList); + } else if (Count == (UINTN)-1) { + return (EFI_NOT_FOUND); + } + + return (EFI_SUCCESS); +} + +/** + Add mappings for any devices without one. Do not change any existing maps. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +ShellCommandUpdateMapping ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleList; + UINTN Count; + EFI_DEVICE_PATH_PROTOCOL **DevicePathList; + CHAR16 *NewDefaultName; + CHAR16 *NewConsistName; + EFI_DEVICE_PATH_PROTOCOL **ConsistMappingTable; + + HandleList = NULL; + Status = EFI_SUCCESS; + + // + // remove mappings that represent removed devices. + // + + // + // Find each handle with Simple File System + // + HandleList = GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid); + if (HandleList != NULL) { + // + // Do a count of the handles + // + for (Count = 0 ; HandleList[Count] != NULL ; Count++); + + // + // Get all Device Paths + // + DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count); + if (DevicePathList == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + for (Count = 0 ; HandleList[Count] != NULL ; Count++) { + DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]); + } + + // + // Sort all DevicePaths + // + PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare); + + ShellCommandConsistMappingInitialize(&ConsistMappingTable); + + // + // Assign new Mappings to remainders + // + for (Count = 0 ; !EFI_ERROR(Status) && HandleList[Count] != NULL && !EFI_ERROR(Status); Count++) { + // + // Skip ones that already have + // + if (gEfiShellProtocol->GetMapFromDevicePath(&DevicePathList[Count]) != NULL) { + continue; + } + // + // Get default name + // + NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeFileSystem); + if (NewDefaultName == NULL) { + Status = EFI_OUT_OF_RESOURCES; + break; + } + + // + // Call shell protocol SetMap function now... + // + Status = gEfiShellProtocol->SetMap(DevicePathList[Count], NewDefaultName); + + if (!EFI_ERROR(Status)) { + // + // Now do consistent name + // + NewConsistName = ShellCommandConsistMappingGenMappingName(DevicePathList[Count], ConsistMappingTable); + if (NewConsistName != NULL) { + Status = gEfiShellProtocol->SetMap(DevicePathList[Count], NewConsistName); + FreePool(NewConsistName); + } + } + + FreePool(NewDefaultName); + } + ShellCommandConsistMappingUnInitialize(ConsistMappingTable); + SHELL_FREE_NON_NULL(HandleList); + SHELL_FREE_NON_NULL(DevicePathList); + + HandleList = NULL; + } else { + Count = (UINTN)-1; + } + // + // Do it all over again for gEfiBlockIoProtocolGuid + // + + return (Status); +} + +/** + Converts a SHELL_FILE_HANDLE to an EFI_FILE_PROTOCOL*. + + @param[in] Handle The SHELL_FILE_HANDLE to convert. + + @return a EFI_FILE_PROTOCOL* representing the same file. +**/ +EFI_FILE_PROTOCOL* +EFIAPI +ConvertShellHandleToEfiFileProtocol( + IN CONST SHELL_FILE_HANDLE Handle + ) +{ + return ((EFI_FILE_PROTOCOL*)(Handle)); +} + +/** + Converts a EFI_FILE_PROTOCOL* to an SHELL_FILE_HANDLE. + + @param[in] Handle The pointer to EFI_FILE_PROTOCOL to convert. + @param[in] Path The path to the file for verification. + + @return A SHELL_FILE_HANDLE representing the same file. + @retval NULL There was not enough memory. +**/ +SHELL_FILE_HANDLE +EFIAPI +ConvertEfiFileProtocolToShellHandle( + IN CONST EFI_FILE_PROTOCOL *Handle, + IN CONST CHAR16 *Path + ) +{ + SHELL_COMMAND_FILE_HANDLE *Buffer; + BUFFER_LIST *NewNode; + + if (Path != NULL) { + Buffer = AllocateZeroPool(sizeof(SHELL_COMMAND_FILE_HANDLE)); + if (Buffer == NULL) { + return (NULL); + } + NewNode = AllocateZeroPool(sizeof(BUFFER_LIST)); + if (NewNode == NULL) { + SHELL_FREE_NON_NULL(Buffer); + return (NULL); + } + Buffer->FileHandle = (EFI_FILE_PROTOCOL*)Handle; + Buffer->Path = StrnCatGrow(&Buffer->Path, NULL, Path, 0); + if (Buffer->Path == NULL) { + SHELL_FREE_NON_NULL(NewNode); + SHELL_FREE_NON_NULL(Buffer); + return (NULL); + } + NewNode->Buffer = Buffer; + + InsertHeadList(&mFileHandleList.Link, &NewNode->Link); + } + return ((SHELL_FILE_HANDLE)(Handle)); +} + +/** + Find the path that was logged with the specified SHELL_FILE_HANDLE. + + @param[in] Handle The SHELL_FILE_HANDLE to query on. + + @return A pointer to the path for the file. +**/ +CONST CHAR16* +EFIAPI +ShellFileHandleGetPath( + IN CONST SHELL_FILE_HANDLE Handle + ) +{ + BUFFER_LIST *Node; + + for (Node = (BUFFER_LIST*)GetFirstNode(&mFileHandleList.Link) + ; !IsNull(&mFileHandleList.Link, &Node->Link) + ; Node = (BUFFER_LIST*)GetNextNode(&mFileHandleList.Link, &Node->Link) + ){ + if ((Node->Buffer) && (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->FileHandle == Handle)){ + return (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->Path); + } + } + return (NULL); +} + +/** + Remove a SHELL_FILE_HANDLE from the list of SHELL_FILE_HANDLES. + + @param[in] Handle The SHELL_FILE_HANDLE to remove. + + @retval TRUE The item was removed. + @retval FALSE The item was not found. +**/ +BOOLEAN +EFIAPI +ShellFileHandleRemove( + IN CONST SHELL_FILE_HANDLE Handle + ) +{ + BUFFER_LIST *Node; + + for (Node = (BUFFER_LIST*)GetFirstNode(&mFileHandleList.Link) + ; !IsNull(&mFileHandleList.Link, &Node->Link) + ; Node = (BUFFER_LIST*)GetNextNode(&mFileHandleList.Link, &Node->Link) + ){ + if ((Node->Buffer) && (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->FileHandle == Handle)){ + RemoveEntryList(&Node->Link); + SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->Path); + SHELL_FREE_NON_NULL(Node->Buffer); + SHELL_FREE_NON_NULL(Node); + return (TRUE); + } + } + return (FALSE); +} + +/** + Function to determine if a SHELL_FILE_HANDLE is at the end of the file. + + This will NOT work on directories. + + If Handle is NULL, then ASSERT. + + @param[in] Handle the file handle + + @retval TRUE the position is at the end of the file + @retval FALSE the position is not at the end of the file +**/ +BOOLEAN +EFIAPI +ShellFileHandleEof( + IN SHELL_FILE_HANDLE Handle + ) +{ + EFI_FILE_INFO *Info; + UINT64 Pos; + BOOLEAN RetVal; + + // + // ASSERT if Handle is NULL + // + ASSERT(Handle != NULL); + + gEfiShellProtocol->GetFilePosition(Handle, &Pos); + Info = gEfiShellProtocol->GetFileInfo (Handle); + gEfiShellProtocol->SetFilePosition(Handle, Pos); + + if (Info == NULL) { + return (FALSE); + } + + if (Pos == Info->FileSize) { + RetVal = TRUE; + } else { + RetVal = FALSE; + } + + FreePool (Info); + + return (RetVal); +} + +/** + Frees any BUFFER_LIST defined type. + + @param[in] List The BUFFER_LIST object to free. +**/ +VOID +EFIAPI +FreeBufferList ( + IN BUFFER_LIST *List + ) +{ + BUFFER_LIST *BufferListEntry; + + if (List == NULL){ + return; + } + // + // enumerate through the buffer list and free all memory + // + for ( BufferListEntry = ( BUFFER_LIST *)GetFirstNode(&List->Link) + ; !IsListEmpty (&List->Link) + ; BufferListEntry = (BUFFER_LIST *)GetFirstNode(&List->Link) + ){ + RemoveEntryList(&BufferListEntry->Link); + if (BufferListEntry->Buffer != NULL) { + FreePool(BufferListEntry->Buffer); + } + FreePool(BufferListEntry); + } +} + +/** + 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. +**/ +VOID +EFIAPI +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] = Hex[TempByte >> 4]; + Val[Index * 3 + 1] = Hex[TempByte & 0xF]; + Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' '); + Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > '~') ? '.' : TempByte); + } + + Val[Index * 3] = 0; + Str[Index] = 0; + ShellPrintEx(-1, -1, L"%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str); + + Data += Size; + Offset += Size; + DataSize -= Size; + } +} + +/** + Dump HEX data into buffer. + + @param[in] Buffer HEX data to be dumped in Buffer. + @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. +**/ +CHAR16* +EFIAPI +CatSDumpHex ( + IN CHAR16 *Buffer, + IN UINTN Indent, + IN UINTN Offset, + IN UINTN DataSize, + IN VOID *UserData + ) +{ + UINT8 *Data; + UINT8 TempByte; + UINTN Size; + UINTN Index; + CHAR8 Val[50]; + CHAR8 Str[20]; + CHAR16 *RetVal; + CHAR16 *TempRetVal; + + Data = UserData; + RetVal = Buffer; + while (DataSize != 0) { + Size = 16; + if (Size > DataSize) { + Size = DataSize; + } + + for (Index = 0; Index < Size; Index += 1) { + TempByte = Data[Index]; + Val[Index * 3 + 0] = Hex[TempByte >> 4]; + Val[Index * 3 + 1] = Hex[TempByte & 0xF]; + Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' '); + Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte); + } + + Val[Index * 3] = 0; + Str[Index] = 0; + TempRetVal = CatSPrint (RetVal, L"%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str); + SHELL_FREE_NON_NULL (RetVal); + RetVal = TempRetVal; + + Data += Size; + Offset += Size; + DataSize -= Size; + } + + return RetVal; +} + +/** + ORDERED_COLLECTION_USER_COMPARE function for SHELL_SORT_UNIQUE_NAME objects. + + @param[in] Unique1AsVoid The first SHELL_SORT_UNIQUE_NAME object (Unique1), + passed in as a pointer-to-VOID. + + @param[in] Unique2AsVoid The second SHELL_SORT_UNIQUE_NAME object (Unique2), + passed in as a pointer-to-VOID. + + @retval <0 If Unique1 compares less than Unique2. + + @retval 0 If Unique1 compares equal to Unique2. + + @retval >0 If Unique1 compares greater than Unique2. +**/ +STATIC +INTN +EFIAPI +UniqueNameCompare ( + IN CONST VOID *Unique1AsVoid, + IN CONST VOID *Unique2AsVoid + ) +{ + CONST SHELL_SORT_UNIQUE_NAME *Unique1; + CONST SHELL_SORT_UNIQUE_NAME *Unique2; + + Unique1 = Unique1AsVoid; + Unique2 = Unique2AsVoid; + + // + // We need to cast away CONST for EFI_UNICODE_COLLATION_STRICOLL. + // + return gUnicodeCollation->StriColl ( + gUnicodeCollation, + (CHAR16 *)Unique1->Alias, + (CHAR16 *)Unique2->Alias + ); +} + +/** + ORDERED_COLLECTION_KEY_COMPARE function for SHELL_SORT_UNIQUE_NAME objects. + + @param[in] UniqueAliasAsVoid The CHAR16 string UniqueAlias, passed in as a + pointer-to-VOID. + + @param[in] UniqueAsVoid The SHELL_SORT_UNIQUE_NAME object (Unique), + passed in as a pointer-to-VOID. + + @retval <0 If UniqueAlias compares less than Unique->Alias. + + @retval 0 If UniqueAlias compares equal to Unique->Alias. + + @retval >0 If UniqueAlias compares greater than Unique->Alias. +**/ +STATIC +INTN +EFIAPI +UniqueNameAliasCompare ( + IN CONST VOID *UniqueAliasAsVoid, + IN CONST VOID *UniqueAsVoid + ) +{ + CONST CHAR16 *UniqueAlias; + CONST SHELL_SORT_UNIQUE_NAME *Unique; + + UniqueAlias = UniqueAliasAsVoid; + Unique = UniqueAsVoid; + + // + // We need to cast away CONST for EFI_UNICODE_COLLATION_STRICOLL. + // + return gUnicodeCollation->StriColl ( + gUnicodeCollation, + (CHAR16 *)UniqueAlias, + (CHAR16 *)Unique->Alias + ); +} + +/** + Sort an EFI_SHELL_FILE_INFO list, optionally moving duplicates to a separate + list. + + @param[in,out] FileList The list of EFI_SHELL_FILE_INFO objects to sort. + + If FileList is NULL on input, then FileList is + considered an empty, hence already sorted, list. + + Otherwise, if (*FileList) is NULL on input, then + EFI_INVALID_PARAMETER is returned. + + Otherwise, the caller is responsible for having + initialized (*FileList)->Link with + InitializeListHead(). No other fields in the + (**FileList) head element are accessed by this + function. + + On output, (*FileList) is sorted according to Order. + If Duplicates is NULL on input, then duplicate + elements are preserved, sorted stably, on + (*FileList). If Duplicates is not NULL on input, + then duplicates are moved (stably sorted) to the + new, dynamically allocated (*Duplicates) list. + + @param[out] Duplicates If Duplicates is NULL on input, (*FileList) will be + a monotonically ordered list on output, with + duplicates stably sorted. + + If Duplicates is not NULL on input, (*FileList) will + be a strictly monotonically oredered list on output, + with duplicates separated (stably sorted) to + (*Duplicates). All fields except Link will be + zero-initialized in the (**Duplicates) head element. + If no duplicates exist, then (*Duplicates) is set to + NULL on output. + + @param[in] Order Determines the comparison operation between + EFI_SHELL_FILE_INFO objects. + + @retval EFI_INVALID_PARAMETER (UINTN)Order is greater than or equal to + (UINTN)ShellSortFileListMax. Neither the + (*FileList) nor the (*Duplicates) list has + been modified. + + @retval EFI_INVALID_PARAMETER (*FileList) was NULL on input. Neither the + (*FileList) nor the (*Duplicates) list has + been modified. + + @retval EFI_OUT_OF_RESOURCES Memory allocation failed. Neither the + (*FileList) nor the (*Duplicates) list has + been modified. + + @retval EFI_SUCCESS Sorting successful, including the case when + FileList is NULL on input. +**/ +EFI_STATUS +EFIAPI +ShellSortFileList ( + IN OUT EFI_SHELL_FILE_INFO **FileList, + OUT EFI_SHELL_FILE_INFO **Duplicates OPTIONAL, + IN SHELL_SORT_FILE_LIST Order + ) +{ + LIST_ENTRY *FilesHead; + ORDERED_COLLECTION *Sort; + LIST_ENTRY *FileEntry; + EFI_SHELL_FILE_INFO *FileInfo; + SHELL_SORT_UNIQUE_NAME *Unique; + EFI_STATUS Status; + EFI_SHELL_FILE_INFO *Dupes; + LIST_ENTRY *NextFileEntry; + CONST CHAR16 *Alias; + ORDERED_COLLECTION_ENTRY *SortEntry; + LIST_ENTRY *TargetFileList; + ORDERED_COLLECTION_ENTRY *NextSortEntry; + VOID *UniqueAsVoid; + + if ((UINTN)Order >= (UINTN)ShellSortFileListMax) { + return EFI_INVALID_PARAMETER; + } + + if (FileList == NULL) { + // + // FileList is considered empty, hence already sorted, with no duplicates. + // + if (Duplicates != NULL) { + *Duplicates = NULL; + } + return EFI_SUCCESS; + } + + if (*FileList == NULL) { + return EFI_INVALID_PARAMETER; + } + FilesHead = &(*FileList)->Link; + + // + // Collect all the unique names. + // + Sort = OrderedCollectionInit (UniqueNameCompare, UniqueNameAliasCompare); + if (Sort == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + BASE_LIST_FOR_EACH (FileEntry, FilesHead) { + FileInfo = (EFI_SHELL_FILE_INFO *)FileEntry; + + // + // Try to record the name of this file as a unique name. + // + Unique = AllocatePool (sizeof (*Unique)); + if (Unique == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto UninitSort; + } + Unique->Alias = ((Order == ShellSortFileListByFileName) ? + FileInfo->FileName : + FileInfo->FullName); + InitializeListHead (&Unique->SameNameList); + + Status = OrderedCollectionInsert (Sort, NULL, Unique); + if (EFI_ERROR (Status)) { + // + // Only two errors are possible: memory allocation failed, or this name + // has been encountered before. In either case, the + // SHELL_SORT_UNIQUE_NAME object being constructed has to be released. + // + FreePool (Unique); + // + // Memory allocation failure is fatal, while having seen the same name + // before is normal. + // + if (Status == EFI_OUT_OF_RESOURCES) { + goto UninitSort; + } + ASSERT (Status == EFI_ALREADY_STARTED); + } + } + + // + // Set Dupes to suppress incorrect compiler/analyzer warnings. + // + Dupes = NULL; + + // + // If separation of duplicates has been requested, allocate the list for + // them. + // + if (Duplicates != NULL) { + Dupes = AllocateZeroPool (sizeof (*Dupes)); + if (Dupes == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto UninitSort; + } + InitializeListHead (&Dupes->Link); + } + + // + // No memory allocation beyond this point; thus, no chance to fail. We can + // now migrate the EFI_SHELL_FILE_INFO objects from (*FileList) to Sort. + // + BASE_LIST_FOR_EACH_SAFE (FileEntry, NextFileEntry, FilesHead) { + FileInfo = (EFI_SHELL_FILE_INFO *)FileEntry; + // + // Look up the SHELL_SORT_UNIQUE_NAME that matches FileInfo's name. + // + Alias = ((Order == ShellSortFileListByFileName) ? + FileInfo->FileName : + FileInfo->FullName); + SortEntry = OrderedCollectionFind (Sort, Alias); + ASSERT (SortEntry != NULL); + Unique = OrderedCollectionUserStruct (SortEntry); + // + // Move FileInfo from (*FileList) to the end of the list of files whose + // names all compare identical to FileInfo's name. + // + RemoveEntryList (&FileInfo->Link); + InsertTailList (&Unique->SameNameList, &FileInfo->Link); + } + + // + // All EFI_SHELL_FILE_INFO objects originally in (*FileList) have been + // distributed to Sort. Now migrate them back to (*FileList), advancing in + // unique name order. + // + for (SortEntry = OrderedCollectionMin (Sort); + SortEntry != NULL; + SortEntry = OrderedCollectionNext (SortEntry)) { + Unique = OrderedCollectionUserStruct (SortEntry); + // + // The first FileInfo encountered for each unique name goes back on + // (*FileList) unconditionally. Further FileInfo instances for the same + // unique name -- that is, duplicates -- are either returned to (*FileList) + // or separated, dependent on the caller's request. + // + TargetFileList = FilesHead; + BASE_LIST_FOR_EACH_SAFE (FileEntry, NextFileEntry, &Unique->SameNameList) { + RemoveEntryList (FileEntry); + InsertTailList (TargetFileList, FileEntry); + if (Duplicates != NULL) { + TargetFileList = &Dupes->Link; + } + } + } + + // + // We're done. If separation of duplicates has been requested, output the + // list of duplicates -- and free that list at once, if it's empty (i.e., if + // no duplicates have been found). + // + if (Duplicates != NULL) { + if (IsListEmpty (&Dupes->Link)) { + FreePool (Dupes); + *Duplicates = NULL; + } else { + *Duplicates = Dupes; + } + } + Status = EFI_SUCCESS; + + // + // Fall through. + // +UninitSort: + for (SortEntry = OrderedCollectionMin (Sort); + SortEntry != NULL; + SortEntry = NextSortEntry) { + NextSortEntry = OrderedCollectionNext (SortEntry); + OrderedCollectionDelete (Sort, SortEntry, &UniqueAsVoid); + Unique = UniqueAsVoid; + ASSERT (IsListEmpty (&Unique->SameNameList)); + FreePool (Unique); + } + OrderedCollectionUninit (Sort); + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.h new file mode 100644 index 00000000..b56aed7c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.h @@ -0,0 +1,84 @@ +/** @file + Provides interface to shell internal functions for shell commands. + + Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _UEFI_COMMAND_LIB_INTERNAL_HEADER_ +#define _UEFI_COMMAND_LIB_INTERNAL_HEADER_ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct{ + LIST_ENTRY Link; + CHAR16 *CommandString; + SHELL_GET_MAN_FILENAME GetManFileName; + SHELL_RUN_COMMAND CommandHandler; + BOOLEAN LastError; + EFI_HII_HANDLE HiiHandle; + EFI_STRING_ID ManFormatHelp; +} SHELL_COMMAND_INTERNAL_LIST_ENTRY; + +typedef struct { + LIST_ENTRY Link; + SCRIPT_FILE *Data; +} SCRIPT_FILE_LIST; + +typedef struct { + EFI_FILE_PROTOCOL *FileHandle; + CHAR16 *Path; +} SHELL_COMMAND_FILE_HANDLE; + +// +// Collects multiple EFI_SHELL_FILE_INFO objects that share the same name. +// +typedef struct { + // + // A string that compares equal to either the FileName or the FullName fields + // of all EFI_SHELL_FILE_INFO objects on SameNameList, according to + // gUnicodeCollation->StriColl(). The string is not dynamically allocated; + // instead, it *aliases* the FileName or FullName field of the + // EFI_SHELL_FILE_INFO object that was first encountered with this name. + // + CONST CHAR16 *Alias; + // + // A list of EFI_SHELL_FILE_INFO objects whose FileName or FullName fields + // compare equal to Alias, according to gUnicodeCollation->StriColl(). + // + LIST_ENTRY SameNameList; +} SHELL_SORT_UNIQUE_NAME; + +#endif //_UEFI_COMMAND_LIB_INTERNAL_HEADER_ + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf new file mode 100644 index 00000000..f27eb4fa --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf @@ -0,0 +1,65 @@ +## @file +# Provides interface to shell internal functions for shell commands. +# +# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiShellCommandLib + FILE_GUID = 5C12F31F-EBAC-466e-A400-FCA8C9EA3A05 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.1 + LIBRARY_CLASS = ShellCommandLib|UEFI_APPLICATION UEFI_DRIVER DXE_RUNTIME_DRIVER + CONSTRUCTOR = ShellCommandLibConstructor + DESTRUCTOR = ShellCommandLibDestructor + +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources.common] + UefiShellCommandLib.c + UefiShellCommandLib.h + ConsistMapping.c + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + PrintLib + UefiBootServicesTableLib + ShellLib + HiiLib + HandleParsingLib + OrderedCollectionLib + +[Protocols] + gEfiUnicodeCollation2ProtocolGuid ## CONSUMES + gEfiShellProtocolGuid ## CONSUMES + gEfiShellParametersProtocolGuid ## CONSUMES + gEfiShellDynamicCommandProtocolGuid ## SOMETIMES_CONSUMES + gEfiUsbIoProtocolGuid ## SOMETIMES_CONSUMES + +[Guids] + gEfiSasDevicePathGuid ## SOMETIMES_CONSUMES ## GUID + +[Pcd.common] + gEfiShellPkgTokenSpaceGuid.PcdShellSupportLevel ## CONSUMES + gEfiShellPkgTokenSpaceGuid.PcdShellMapNameLength ## CONSUMES + gEfiShellPkgTokenSpaceGuid.PcdUsbExtendedDecode ## SOMETIMES_CONSUMES + gEfiShellPkgTokenSpaceGuid.PcdShellDecodeIScsiMapNames ## SOMETIMES_CONSUMES + gEfiShellPkgTokenSpaceGuid.PcdShellVendorExtendedDecode ## SOMETIMES_CONSUMES + +[Depex] + gEfiUnicodeCollation2ProtocolGuid diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Comp.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Comp.c new file mode 100644 index 00000000..a0d454ad --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Comp.c @@ -0,0 +1,493 @@ +/** @file + Main file for Comp shell Debug1 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDebug1CommandsLib.h" + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-n", TypeValue}, + {L"-s", TypeValue}, + {NULL, TypeMax} + }; + +typedef enum { + OutOfDiffPoint, + InDiffPoint, + InPrevDiffPoint +} READ_STATUS; + +// +// Buffer type, for reading both file operands in chunks. +// +typedef struct { + UINT8 *Data; // dynamically allocated buffer + UINTN Allocated; // the allocated size of Data + UINTN Next; // next position in Data to fetch a byte at + UINTN Left; // number of bytes left in Data for fetching at Next +} FILE_BUFFER; + +/** + Function to print differnt point data. + + @param[in] FileName File name. + @param[in] FileTag File tag name. + @param[in] Buffer Data buffer to be printed. + @param[in] BufferSize Size of the data to be printed. + @param[in] Address Address of the differnt point. + @param[in] DifferentBytes Total size of the buffer. + +**/ +VOID +PrintDifferentPoint( + CONST CHAR16 *FileName, + CHAR16 *FileTag, + UINT8 *Buffer, + UINT64 BufferSize, + UINTN Address, + UINT64 DifferentBytes + ) +{ + UINTN Index; + + ShellPrintEx (-1, -1, L"%s: %s\r\n %08x:", FileTag, FileName, Address); + + // + // Print data in hex-format. + // + for (Index = 0; Index < BufferSize; Index++) { + ShellPrintEx (-1, -1, L" %02x", Buffer[Index]); + } + + if (BufferSize < DifferentBytes) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_COMP_END_OF_FILE), gShellDebug1HiiHandle); + } + + ShellPrintEx (-1, -1, L" *"); + + // + // Print data in char-format. + // + for (Index = 0; Index < BufferSize; Index++) { + if (Buffer[Index] >= 0x20 && Buffer[Index] <= 0x7E) { + ShellPrintEx (-1, -1, L"%c", Buffer[Index]); + } else { + // + // Print dots for control characters + // + ShellPrintEx (-1, -1, L"."); + } + } + + ShellPrintEx (-1, -1, L"*\r\n"); +} + +/** + Initialize a FILE_BUFFER. + + @param[out] FileBuffer The FILE_BUFFER to initialize. On return, the caller + is responsible for checking FileBuffer->Data: if + FileBuffer->Data is NULL on output, then memory + allocation failed. +**/ +STATIC +VOID +FileBufferInit ( + OUT FILE_BUFFER *FileBuffer + ) +{ + FileBuffer->Allocated = PcdGet32 (PcdShellFileOperationSize); + FileBuffer->Data = AllocatePool (FileBuffer->Allocated); + FileBuffer->Left = 0; +} + +/** + Uninitialize a FILE_BUFFER. + + @param[in,out] FileBuffer The FILE_BUFFER to uninitialize. The caller is + responsible for making sure FileBuffer was first + initialized with FileBufferInit(), successfully or + unsuccessfully. +**/ +STATIC +VOID +FileBufferUninit ( + IN OUT FILE_BUFFER *FileBuffer + ) +{ + SHELL_FREE_NON_NULL (FileBuffer->Data); +} + +/** + Read a byte from a SHELL_FILE_HANDLE, buffered with a FILE_BUFFER. + + @param[in] FileHandle The SHELL_FILE_HANDLE to replenish FileBuffer + from, if needed. + + @param[in,out] FileBuffer The FILE_BUFFER to read a byte from. If FileBuffer + is empty on entry, then FileBuffer is refilled + from FileHandle, before outputting a byte from + FileBuffer to Byte. The caller is responsible for + ensuring that FileBuffer was successfully + initialized with FileBufferInit(). + + @param[out] BytesRead On successful return, BytesRead is set to 1 if the + next byte from FileBuffer has been stored to Byte. + On successful return, BytesRead is set to 0 if + FileBuffer is empty, and FileHandle is at EOF. + When an error is returned, BytesRead is not set. + + @param[out] Byte On output, the next byte from FileBuffer. Only set + if (a) EFI_SUCCESS is returned and (b) BytesRead + is set to 1 on output. + + @retval EFI_SUCCESS BytesRead has been set to 0 or 1. In the latter case, + Byte has been set as well. + + @return Error codes propagated from + gEfiShellProtocol->ReadFile(). +**/ +STATIC +EFI_STATUS +FileBufferReadByte ( + IN SHELL_FILE_HANDLE FileHandle, + IN OUT FILE_BUFFER *FileBuffer, + OUT UINTN *BytesRead, + OUT UINT8 *Byte + ) +{ + UINTN ReadSize; + EFI_STATUS Status; + + if (FileBuffer->Left == 0) { + ReadSize = FileBuffer->Allocated; + Status = gEfiShellProtocol->ReadFile (FileHandle, &ReadSize, + FileBuffer->Data); + if (EFI_ERROR (Status)) { + return Status; + } + if (ReadSize == 0) { + *BytesRead = 0; + return EFI_SUCCESS; + } + FileBuffer->Next = 0; + FileBuffer->Left = ReadSize; + } + + *BytesRead = 1; + *Byte = FileBuffer->Data[FileBuffer->Next]; + + FileBuffer->Next++; + FileBuffer->Left--; + return EFI_SUCCESS; +} + +/** + Function for 'comp' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunComp ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + CHAR16 *FileName1; + CHAR16 *FileName2; + CONST CHAR16 *TempParam; + SHELL_STATUS ShellStatus; + SHELL_FILE_HANDLE FileHandle1; + SHELL_FILE_HANDLE FileHandle2; + UINT64 Size1; + UINT64 Size2; + UINT64 DifferentBytes; + UINT64 DifferentCount; + UINT8 DiffPointNumber; + UINT8 OneByteFromFile1; + UINT8 OneByteFromFile2; + UINT8 *DataFromFile1; + UINT8 *DataFromFile2; + FILE_BUFFER FileBuffer1; + FILE_BUFFER FileBuffer2; + UINTN InsertPosition1; + UINTN InsertPosition2; + UINTN DataSizeFromFile1; + UINTN DataSizeFromFile2; + UINTN TempAddress; + UINTN Index; + UINTN DiffPointAddress; + READ_STATUS ReadStatus; + + ShellStatus = SHELL_SUCCESS; + Status = EFI_SUCCESS; + FileName1 = NULL; + FileName2 = NULL; + FileHandle1 = NULL; + FileHandle2 = NULL; + DataFromFile1 = NULL; + DataFromFile2 = NULL; + ReadStatus = OutOfDiffPoint; + DifferentCount = 10; + DifferentBytes = 4; + DiffPointNumber = 0; + InsertPosition1 = 0; + InsertPosition2 = 0; + TempAddress = 0; + DiffPointAddress = 0; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"comp", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetCount(Package) > 3) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"comp"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetCount(Package) < 3) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"comp"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + TempParam = ShellCommandLineGetRawValue(Package, 1); + ASSERT(TempParam != NULL); + FileName1 = ShellFindFilePath(TempParam); + if (FileName1 == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_FILE_FIND_FAIL), gShellDebug1HiiHandle, L"comp", TempParam); + ShellStatus = SHELL_NOT_FOUND; + } else { + Status = ShellOpenFileByName(FileName1, &FileHandle1, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"comp", TempParam); + ShellStatus = SHELL_NOT_FOUND; + } + } + TempParam = ShellCommandLineGetRawValue(Package, 2); + ASSERT(TempParam != NULL); + FileName2 = ShellFindFilePath(TempParam); + if (FileName2 == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_FILE_FIND_FAIL), gShellDebug1HiiHandle, L"comp", TempParam); + ShellStatus = SHELL_NOT_FOUND; + } else { + Status = ShellOpenFileByName(FileName2, &FileHandle2, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"comp", TempParam); + ShellStatus = SHELL_NOT_FOUND; + } + } + if (ShellStatus == SHELL_SUCCESS) { + Status = gEfiShellProtocol->GetFileSize(FileHandle1, &Size1); + ASSERT_EFI_ERROR(Status); + Status = gEfiShellProtocol->GetFileSize(FileHandle2, &Size2); + ASSERT_EFI_ERROR(Status); + + if (ShellCommandLineGetFlag (Package, L"-n")) { + TempParam = ShellCommandLineGetValue (Package, L"-n"); + if (TempParam == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDebug1HiiHandle, L"comp", L"-n"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + if (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16 *)TempParam, L"all") == 0) { + DifferentCount = MAX_UINTN; + } else { + Status = ShellConvertStringToUint64 (TempParam, &DifferentCount, FALSE, TRUE); + if (EFI_ERROR(Status) || DifferentCount == 0) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellDebug1HiiHandle, L"comp", TempParam, L"-n"); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } + } + } + + if (ShellCommandLineGetFlag (Package, L"-s")) { + TempParam = ShellCommandLineGetValue (Package, L"-s"); + if (TempParam == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDebug1HiiHandle, L"comp", L"-s"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = ShellConvertStringToUint64 (TempParam, &DifferentBytes, FALSE, TRUE); + if (EFI_ERROR(Status) || DifferentBytes == 0) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellDebug1HiiHandle, L"comp", TempParam, L"-s"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + if (DifferentBytes > MAX (Size1, Size2)) { + DifferentBytes = MAX (Size1, Size2); + } + } + } + } + } + + if (ShellStatus == SHELL_SUCCESS) { + DataFromFile1 = AllocateZeroPool ((UINTN)DifferentBytes); + DataFromFile2 = AllocateZeroPool ((UINTN)DifferentBytes); + FileBufferInit (&FileBuffer1); + FileBufferInit (&FileBuffer2); + if (DataFromFile1 == NULL || DataFromFile2 == NULL || + FileBuffer1.Data == NULL || FileBuffer2.Data == NULL) { + ShellStatus = SHELL_OUT_OF_RESOURCES; + SHELL_FREE_NON_NULL (DataFromFile1); + SHELL_FREE_NON_NULL (DataFromFile2); + FileBufferUninit (&FileBuffer1); + FileBufferUninit (&FileBuffer2); + } + } + + if (ShellStatus == SHELL_SUCCESS) { + while (DiffPointNumber < DifferentCount) { + DataSizeFromFile1 = 1; + DataSizeFromFile2 = 1; + OneByteFromFile1 = 0; + OneByteFromFile2 = 0; + Status = FileBufferReadByte (FileHandle1, &FileBuffer1, + &DataSizeFromFile1, &OneByteFromFile1); + ASSERT_EFI_ERROR (Status); + Status = FileBufferReadByte (FileHandle2, &FileBuffer2, + &DataSizeFromFile2, &OneByteFromFile2); + ASSERT_EFI_ERROR (Status); + + TempAddress++; + + // + // 1.When end of file and no chars in DataFromFile buffer, then break while. + // 2.If no more char in File1 or File2, The ReadStatus is InPrevDiffPoint forever. + // So the previous different point is the last one, then break the while block. + // + if ( (DataSizeFromFile1 == 0 && InsertPosition1 == 0 && DataSizeFromFile2 == 0 && InsertPosition2 == 0) || + (ReadStatus == InPrevDiffPoint && (DataSizeFromFile1 == 0 || DataSizeFromFile2 == 0)) + ) { + break; + } + + if (ReadStatus == OutOfDiffPoint) { + if (OneByteFromFile1 != OneByteFromFile2) { + ReadStatus = InDiffPoint; + DiffPointAddress = TempAddress; + if (DataSizeFromFile1 == 1) { + DataFromFile1[InsertPosition1++] = OneByteFromFile1; + } + if (DataSizeFromFile2 == 1) { + DataFromFile2[InsertPosition2++] = OneByteFromFile2; + } + } + } else if (ReadStatus == InDiffPoint) { + if (DataSizeFromFile1 == 1) { + DataFromFile1[InsertPosition1++] = OneByteFromFile1; + } + if (DataSizeFromFile2 == 1) { + DataFromFile2[InsertPosition2++] = OneByteFromFile2; + } + } else if (ReadStatus == InPrevDiffPoint) { + if (OneByteFromFile1 == OneByteFromFile2) { + ReadStatus = OutOfDiffPoint; + } + } + + // + // ReadStatus should be always equal InDiffPoint. + // + if ( InsertPosition1 == DifferentBytes || + InsertPosition2 == DifferentBytes || + (DataSizeFromFile1 == 0 && DataSizeFromFile2 == 0) + ) { + + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_COMP_DIFFERENCE_POINT), gShellDebug1HiiHandle, ++DiffPointNumber); + PrintDifferentPoint (FileName1, L"File1", DataFromFile1, InsertPosition1, DiffPointAddress, DifferentBytes); + PrintDifferentPoint (FileName2, L"File2", DataFromFile2, InsertPosition2, DiffPointAddress, DifferentBytes); + + // + // One of two buffuers is empty, it means this is the last different point. + // + if (InsertPosition1 == 0 || InsertPosition2 == 0) { + break; + } + + for (Index = 1; Index < InsertPosition1 && Index < InsertPosition2; Index++) { + if (DataFromFile1[Index] == DataFromFile2[Index]) { + ReadStatus = OutOfDiffPoint; + break; + } + } + + if (ReadStatus == OutOfDiffPoint) { + // + // Try to find a new different point in the rest of DataFromFile. + // + for (; Index < MAX (InsertPosition1,InsertPosition2); Index++) { + if (DataFromFile1[Index] != DataFromFile2[Index]) { + ReadStatus = InDiffPoint; + DiffPointAddress += Index; + break; + } + } + } else { + // + // Doesn't find a new different point, still in the same different point. + // + ReadStatus = InPrevDiffPoint; + } + + CopyMem (DataFromFile1, DataFromFile1 + Index, InsertPosition1 - Index); + CopyMem (DataFromFile2, DataFromFile2 + Index, InsertPosition2 - Index); + + SetMem (DataFromFile1 + InsertPosition1 - Index, (UINTN)DifferentBytes - InsertPosition1 + Index, 0); + SetMem (DataFromFile2 + InsertPosition2 - Index, (UINTN)DifferentBytes - InsertPosition2 + Index, 0); + + InsertPosition1 -= Index; + InsertPosition2 -= Index; + } + } + + SHELL_FREE_NON_NULL (DataFromFile1); + SHELL_FREE_NON_NULL (DataFromFile2); + FileBufferUninit (&FileBuffer1); + FileBufferUninit (&FileBuffer2); + + if (DiffPointNumber == 0) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_COMP_FOOTER_PASS), gShellDebug1HiiHandle); + } else { + ShellStatus = SHELL_NOT_EQUAL; + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_COMP_FOOTER_FAIL), gShellDebug1HiiHandle); + } + } + } + + ShellCommandLineFreeVarList (Package); + } + SHELL_FREE_NON_NULL(FileName1); + SHELL_FREE_NON_NULL(FileName2); + + if (FileHandle1 != NULL) { + gEfiShellProtocol->CloseFile(FileHandle1); + } + if (FileHandle2 != NULL) { + gEfiShellProtocol->CloseFile(FileHandle2); + } + + return (ShellStatus); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Compress.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Compress.c new file mode 100644 index 00000000..6b263535 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Compress.c @@ -0,0 +1,1382 @@ +/** @file + Main file for compression routine. + + Compression routine. The compression algorithm is a mixture of + LZ77 and Huffman coding. LZ77 transforms the source data into a + sequence of Original Characters and Pointers to repeated strings. + This sequence is further divided into Blocks and Huffman codings + are applied to each Block. + + Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include +#include +#include +#include +#include + +#include "Compress.h" + +// +// Macro Definitions +// +typedef INT16 NODE; +#define UINT8_MAX 0xff +#define UINT8_BIT 8 +#define THRESHOLD 3 +#define INIT_CRC 0 +#define WNDBIT 13 +#define WNDSIZ (1U << WNDBIT) +#define MAXMATCH 256 +#define BLKSIZ (1U << 14) // 16 * 1024U +#define PERC_FLAG 0x8000U +#define CODE_BIT 16 +#define NIL 0 +#define MAX_HASH_VAL (3 * WNDSIZ + (WNDSIZ / 512 + 1) * UINT8_MAX) +#define HASH(LoopVar7, LoopVar5) ((LoopVar7) + ((LoopVar5) << (WNDBIT - 9)) + WNDSIZ * 2) +#define CRCPOLY 0xA001 +#define UPDATE_CRC(LoopVar5) mCrc = mCrcTable[(mCrc ^ (LoopVar5)) & 0xFF] ^ (mCrc >> UINT8_BIT) + +// +// C: the Char&Len Set; P: the Position Set; T: the exTra Set +// +#define NC (UINT8_MAX + MAXMATCH + 2 - THRESHOLD) +#define CBIT 9 +#define NP (WNDBIT + 1) +#define PBIT 4 +#define NT (CODE_BIT + 3) +#define TBIT 5 +#if NT > NP + #define NPT NT +#else + #define NPT NP +#endif +// +// Function Prototypes +// + +/** + Put a dword to output stream + + @param[in] Data The dword to put. +**/ +VOID +PutDword( + IN UINT32 Data + ); + +// +// Global Variables +// +STATIC UINT8 *mSrc; +STATIC UINT8 *mDst; +STATIC UINT8 *mSrcUpperLimit; +STATIC UINT8 *mDstUpperLimit; + +STATIC UINT8 *mLevel; +STATIC UINT8 *mText; +STATIC UINT8 *mChildCount; +STATIC UINT8 *mBuf; +STATIC UINT8 mCLen[NC]; +STATIC UINT8 mPTLen[NPT]; +STATIC UINT8 *mLen; +STATIC INT16 mHeap[NC + 1]; +STATIC INT32 mRemainder; +STATIC INT32 mMatchLen; +STATIC INT32 mBitCount; +STATIC INT32 mHeapSize; +STATIC INT32 mTempInt32; +STATIC UINT32 mBufSiz = 0; +STATIC UINT32 mOutputPos; +STATIC UINT32 mOutputMask; +STATIC UINT32 mSubBitBuf; +STATIC UINT32 mCrc; +STATIC UINT32 mCompSize; +STATIC UINT32 mOrigSize; + +STATIC UINT16 *mFreq; +STATIC UINT16 *mSortPtr; +STATIC UINT16 mLenCnt[17]; +STATIC UINT16 mLeft[2 * NC - 1]; +STATIC UINT16 mRight[2 * NC - 1]; +STATIC UINT16 mCrcTable[UINT8_MAX + 1]; +STATIC UINT16 mCFreq[2 * NC - 1]; +STATIC UINT16 mCCode[NC]; +STATIC UINT16 mPFreq[2 * NP - 1]; +STATIC UINT16 mPTCode[NPT]; +STATIC UINT16 mTFreq[2 * NT - 1]; + +STATIC NODE mPos; +STATIC NODE mMatchPos; +STATIC NODE mAvail; +STATIC NODE *mPosition; +STATIC NODE *mParent; +STATIC NODE *mPrev; +STATIC NODE *mNext = NULL; +INT32 mHuffmanDepth = 0; + +/** + Make a CRC table. + +**/ +VOID +MakeCrcTable ( + VOID + ) +{ + UINT32 LoopVar1; + + UINT32 LoopVar2; + + UINT32 LoopVar4; + + for (LoopVar1 = 0; LoopVar1 <= UINT8_MAX; LoopVar1++) { + LoopVar4 = LoopVar1; + for (LoopVar2 = 0; LoopVar2 < UINT8_BIT; LoopVar2++) { + if ((LoopVar4 & 1) != 0) { + LoopVar4 = (LoopVar4 >> 1) ^ CRCPOLY; + } else { + LoopVar4 >>= 1; + } + } + + mCrcTable[LoopVar1] = (UINT16) LoopVar4; + } +} + +/** + Put a dword to output stream + + @param[in] Data The dword to put. +**/ +VOID +PutDword ( + IN UINT32 Data + ) +{ + if (mDst < mDstUpperLimit) { + *mDst++ = (UINT8) (((UINT8) (Data)) & 0xff); + } + + if (mDst < mDstUpperLimit) { + *mDst++ = (UINT8) (((UINT8) (Data >> 0x08)) & 0xff); + } + + if (mDst < mDstUpperLimit) { + *mDst++ = (UINT8) (((UINT8) (Data >> 0x10)) & 0xff); + } + + if (mDst < mDstUpperLimit) { + *mDst++ = (UINT8) (((UINT8) (Data >> 0x18)) & 0xff); + } +} + +/** + Allocate memory spaces for data structures used in compression process. + + @retval EFI_SUCCESS Memory was allocated successfully. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +AllocateMemory ( + VOID + ) +{ + mText = AllocateZeroPool (WNDSIZ * 2 + MAXMATCH); + mLevel = AllocateZeroPool ((WNDSIZ + UINT8_MAX + 1) * sizeof (*mLevel)); + mChildCount = AllocateZeroPool ((WNDSIZ + UINT8_MAX + 1) * sizeof (*mChildCount)); + mPosition = AllocateZeroPool ((WNDSIZ + UINT8_MAX + 1) * sizeof (*mPosition)); + mParent = AllocateZeroPool (WNDSIZ * 2 * sizeof (*mParent)); + mPrev = AllocateZeroPool (WNDSIZ * 2 * sizeof (*mPrev)); + mNext = AllocateZeroPool ((MAX_HASH_VAL + 1) * sizeof (*mNext)); + + mBufSiz = BLKSIZ; + mBuf = AllocateZeroPool (mBufSiz); + while (mBuf == NULL) { + mBufSiz = (mBufSiz / 10U) * 9U; + if (mBufSiz < 4 * 1024U) { + return EFI_OUT_OF_RESOURCES; + } + + mBuf = AllocateZeroPool (mBufSiz); + } + + mBuf[0] = 0; + + return EFI_SUCCESS; +} + +/** + Called when compression is completed to free memory previously allocated. + +**/ +VOID +FreeMemory ( + VOID + ) +{ + SHELL_FREE_NON_NULL (mText); + SHELL_FREE_NON_NULL (mLevel); + SHELL_FREE_NON_NULL (mChildCount); + SHELL_FREE_NON_NULL (mPosition); + SHELL_FREE_NON_NULL (mParent); + SHELL_FREE_NON_NULL (mPrev); + SHELL_FREE_NON_NULL (mNext); + SHELL_FREE_NON_NULL (mBuf); +} + +/** + Initialize String Info Log data structures. +**/ +VOID +InitSlide ( + VOID + ) +{ + NODE LoopVar1; + + SetMem (mLevel + WNDSIZ, (UINT8_MAX + 1) * sizeof (UINT8), 1); + SetMem (mPosition + WNDSIZ, (UINT8_MAX + 1) * sizeof (NODE), 0); + + SetMem (mParent + WNDSIZ, WNDSIZ * sizeof (NODE), 0); + + mAvail = 1; + for (LoopVar1 = 1; LoopVar1 < WNDSIZ - 1; LoopVar1++) { + mNext[LoopVar1] = (NODE) (LoopVar1 + 1); + } + + mNext[WNDSIZ - 1] = NIL; + SetMem (mNext + WNDSIZ * 2, (MAX_HASH_VAL - WNDSIZ * 2 + 1) * sizeof (NODE), 0); +} + +/** + Find child node given the parent node and the edge character + + @param[in] LoopVar6 The parent node. + @param[in] LoopVar5 The edge character. + + @return The child node. + @retval NIL(Zero) No child could be found. + +**/ +NODE +Child ( + IN NODE LoopVar6, + IN UINT8 LoopVar5 + ) +{ + NODE LoopVar4; + + LoopVar4 = mNext[HASH (LoopVar6, LoopVar5)]; + mParent[NIL] = LoopVar6; /* sentinel */ + while (mParent[LoopVar4] != LoopVar6) { + LoopVar4 = mNext[LoopVar4]; + } + + return LoopVar4; +} + +/** + Create a new child for a given parent node. + + @param[in] LoopVar6 The parent node. + @param[in] LoopVar5 The edge character. + @param[in] LoopVar4 The child node. +**/ +VOID +MakeChild ( + IN NODE LoopVar6, + IN UINT8 LoopVar5, + IN NODE LoopVar4 + ) +{ + NODE LoopVar12; + + NODE LoopVar10; + + LoopVar12 = (NODE) HASH (LoopVar6, LoopVar5); + LoopVar10 = mNext[LoopVar12]; + mNext[LoopVar12] = LoopVar4; + mNext[LoopVar4] = LoopVar10; + mPrev[LoopVar10] = LoopVar4; + mPrev[LoopVar4] = LoopVar12; + mParent[LoopVar4] = LoopVar6; + mChildCount[LoopVar6]++; +} + +/** + Split a node. + + @param[in] Old The node to split. +**/ +VOID +Split ( + IN NODE Old + ) +{ + NODE New; + + NODE LoopVar10; + + New = mAvail; + mAvail = mNext[New]; + mChildCount[New] = 0; + LoopVar10 = mPrev[Old]; + mPrev[New] = LoopVar10; + mNext[LoopVar10] = New; + LoopVar10 = mNext[Old]; + mNext[New] = LoopVar10; + mPrev[LoopVar10] = New; + mParent[New] = mParent[Old]; + mLevel[New] = (UINT8) mMatchLen; + mPosition[New] = mPos; + MakeChild (New, mText[mMatchPos + mMatchLen], Old); + MakeChild (New, mText[mPos + mMatchLen], mPos); +} + +/** + Insert string info for current position into the String Info Log. + +**/ +VOID +InsertNode ( + VOID + ) +{ + NODE LoopVar6; + + NODE LoopVar4; + + NODE LoopVar2; + + NODE LoopVar10; + UINT8 LoopVar5; + UINT8 *TempString3; + UINT8 *TempString2; + + if (mMatchLen >= 4) { + // + // We have just got a long match, the target tree + // can be located by MatchPos + 1. Travese the tree + // from bottom up to get to a proper starting point. + // The usage of PERC_FLAG ensures proper node deletion + // in DeleteNode() later. + // + mMatchLen--; + LoopVar4 = (NODE) ((mMatchPos + 1) | WNDSIZ); + LoopVar6 = mParent[LoopVar4]; + while (LoopVar6 == NIL) { + LoopVar4 = mNext[LoopVar4]; + LoopVar6 = mParent[LoopVar4]; + } + + while (mLevel[LoopVar6] >= mMatchLen) { + LoopVar4 = LoopVar6; + LoopVar6 = mParent[LoopVar6]; + } + + LoopVar10 = LoopVar6; + while (mPosition[LoopVar10] < 0) { + mPosition[LoopVar10] = mPos; + LoopVar10 = mParent[LoopVar10]; + } + + if (LoopVar10 < WNDSIZ) { + mPosition[LoopVar10] = (NODE) (mPos | PERC_FLAG); + } + } else { + // + // Locate the target tree + // + LoopVar6 = (NODE) (mText[mPos] + WNDSIZ); + LoopVar5 = mText[mPos + 1]; + LoopVar4 = Child (LoopVar6, LoopVar5); + if (LoopVar4 == NIL) { + MakeChild (LoopVar6, LoopVar5, mPos); + mMatchLen = 1; + return ; + } + + mMatchLen = 2; + } + // + // Traverse down the tree to find a match. + // Update Position value along the route. + // Node split or creation is involved. + // + for (;;) { + if (LoopVar4 >= WNDSIZ) { + LoopVar2 = MAXMATCH; + mMatchPos = LoopVar4; + } else { + LoopVar2 = mLevel[LoopVar4]; + mMatchPos = (NODE) (mPosition[LoopVar4] & ~PERC_FLAG); + } + + if (mMatchPos >= mPos) { + mMatchPos -= WNDSIZ; + } + + TempString3 = &mText[mPos + mMatchLen]; + TempString2 = &mText[mMatchPos + mMatchLen]; + while (mMatchLen < LoopVar2) { + if (*TempString3 != *TempString2) { + Split (LoopVar4); + return ; + } + + mMatchLen++; + TempString3++; + TempString2++; + } + + if (mMatchLen >= MAXMATCH) { + break; + } + + mPosition[LoopVar4] = mPos; + LoopVar6 = LoopVar4; + LoopVar4 = Child (LoopVar6, *TempString3); + if (LoopVar4 == NIL) { + MakeChild (LoopVar6, *TempString3, mPos); + return ; + } + + mMatchLen++; + } + + LoopVar10 = mPrev[LoopVar4]; + mPrev[mPos] = LoopVar10; + mNext[LoopVar10] = mPos; + LoopVar10 = mNext[LoopVar4]; + mNext[mPos] = LoopVar10; + mPrev[LoopVar10] = mPos; + mParent[mPos] = LoopVar6; + mParent[LoopVar4] = NIL; + + // + // Special usage of 'next' + // + mNext[LoopVar4] = mPos; + +} + +/** + Delete outdated string info. (The Usage of PERC_FLAG + ensures a clean deletion). + +**/ +VOID +DeleteNode ( + VOID + ) +{ + NODE LoopVar6; + + NODE LoopVar4; + + NODE LoopVar11; + + NODE LoopVar10; + + NODE LoopVar9; + + if (mParent[mPos] == NIL) { + return ; + } + + LoopVar4 = mPrev[mPos]; + LoopVar11 = mNext[mPos]; + mNext[LoopVar4] = LoopVar11; + mPrev[LoopVar11] = LoopVar4; + LoopVar4 = mParent[mPos]; + mParent[mPos] = NIL; + if (LoopVar4 >= WNDSIZ) { + return ; + } + + mChildCount[LoopVar4]--; + if (mChildCount[LoopVar4] > 1) { + return ; + } + + LoopVar10 = (NODE) (mPosition[LoopVar4] & ~PERC_FLAG); + if (LoopVar10 >= mPos) { + LoopVar10 -= WNDSIZ; + } + + LoopVar11 = LoopVar10; + LoopVar6 = mParent[LoopVar4]; + LoopVar9 = mPosition[LoopVar6]; + while ((LoopVar9 & PERC_FLAG) != 0){ + LoopVar9 &= ~PERC_FLAG; + if (LoopVar9 >= mPos) { + LoopVar9 -= WNDSIZ; + } + + if (LoopVar9 > LoopVar11) { + LoopVar11 = LoopVar9; + } + + mPosition[LoopVar6] = (NODE) (LoopVar11 | WNDSIZ); + LoopVar6 = mParent[LoopVar6]; + LoopVar9 = mPosition[LoopVar6]; + } + + if (LoopVar6 < WNDSIZ) { + if (LoopVar9 >= mPos) { + LoopVar9 -= WNDSIZ; + } + + if (LoopVar9 > LoopVar11) { + LoopVar11 = LoopVar9; + } + + mPosition[LoopVar6] = (NODE) (LoopVar11 | WNDSIZ | PERC_FLAG); + } + + LoopVar11 = Child (LoopVar4, mText[LoopVar10 + mLevel[LoopVar4]]); + LoopVar10 = mPrev[LoopVar11]; + LoopVar9 = mNext[LoopVar11]; + mNext[LoopVar10] = LoopVar9; + mPrev[LoopVar9] = LoopVar10; + LoopVar10 = mPrev[LoopVar4]; + mNext[LoopVar10] = LoopVar11; + mPrev[LoopVar11] = LoopVar10; + LoopVar10 = mNext[LoopVar4]; + mPrev[LoopVar10] = LoopVar11; + mNext[LoopVar11] = LoopVar10; + mParent[LoopVar11] = mParent[LoopVar4]; + mParent[LoopVar4] = NIL; + mNext[LoopVar4] = mAvail; + mAvail = LoopVar4; +} + +/** + Read in source data + + @param[out] LoopVar7 The buffer to hold the data. + @param[in] LoopVar8 The number of bytes to read. + + @return The number of bytes actually read. +**/ +INT32 +FreadCrc ( + OUT UINT8 *LoopVar7, + IN INT32 LoopVar8 + ) +{ + INT32 LoopVar1; + + for (LoopVar1 = 0; mSrc < mSrcUpperLimit && LoopVar1 < LoopVar8; LoopVar1++) { + *LoopVar7++ = *mSrc++; + } + + LoopVar8 = LoopVar1; + + LoopVar7 -= LoopVar8; + mOrigSize += LoopVar8; + LoopVar1--; + while (LoopVar1 >= 0) { + UPDATE_CRC (*LoopVar7++); + LoopVar1--; + } + + return LoopVar8; +} + +/** + Advance the current position (read in new data if needed). + Delete outdated string info. Find a match string for current position. + + @retval TRUE The operation was successful. + @retval FALSE The operation failed due to insufficient memory. +**/ +BOOLEAN +GetNextMatch ( + VOID + ) +{ + INT32 LoopVar8; + VOID *Temp; + + mRemainder--; + mPos++; + if (mPos == WNDSIZ * 2) { + Temp = AllocateZeroPool (WNDSIZ + MAXMATCH); + if (Temp == NULL) { + return (FALSE); + } + CopyMem (Temp, &mText[WNDSIZ], WNDSIZ + MAXMATCH); + CopyMem (&mText[0], Temp, WNDSIZ + MAXMATCH); + FreePool (Temp); + LoopVar8 = FreadCrc (&mText[WNDSIZ + MAXMATCH], WNDSIZ); + mRemainder += LoopVar8; + mPos = WNDSIZ; + } + + DeleteNode (); + InsertNode (); + + return (TRUE); +} + +/** + Send entry LoopVar1 down the queue. + + @param[in] LoopVar1 The index of the item to move. +**/ +VOID +DownHeap ( + IN INT32 i + ) +{ + INT32 LoopVar1; + + INT32 LoopVar2; + + // + // priority queue: send i-th entry down heap + // + LoopVar2 = mHeap[i]; + LoopVar1 = 2 * i; + while (LoopVar1 <= mHeapSize) { + if (LoopVar1 < mHeapSize && mFreq[mHeap[LoopVar1]] > mFreq[mHeap[LoopVar1 + 1]]) { + LoopVar1++; + } + + if (mFreq[LoopVar2] <= mFreq[mHeap[LoopVar1]]) { + break; + } + + mHeap[i] = mHeap[LoopVar1]; + i = LoopVar1; + LoopVar1 = 2 * i; + } + + mHeap[i] = (INT16) LoopVar2; +} + +/** + Count the number of each code length for a Huffman tree. + + @param[in] LoopVar1 The top node. +**/ +VOID +CountLen ( + IN INT32 LoopVar1 + ) +{ + if (LoopVar1 < mTempInt32) { + mLenCnt[(mHuffmanDepth < 16) ? mHuffmanDepth : 16]++; + } else { + mHuffmanDepth++; + CountLen (mLeft[LoopVar1]); + CountLen (mRight[LoopVar1]); + mHuffmanDepth--; + } +} + +/** + Create code length array for a Huffman tree. + + @param[in] Root The root of the tree. +**/ +VOID +MakeLen ( + IN INT32 Root + ) +{ + INT32 LoopVar1; + + INT32 LoopVar2; + UINT32 Cum; + + for (LoopVar1 = 0; LoopVar1 <= 16; LoopVar1++) { + mLenCnt[LoopVar1] = 0; + } + + CountLen (Root); + + // + // Adjust the length count array so that + // no code will be generated longer than its designated length + // + Cum = 0; + for (LoopVar1 = 16; LoopVar1 > 0; LoopVar1--) { + Cum += mLenCnt[LoopVar1] << (16 - LoopVar1); + } + + while (Cum != (1U << 16)) { + mLenCnt[16]--; + for (LoopVar1 = 15; LoopVar1 > 0; LoopVar1--) { + if (mLenCnt[LoopVar1] != 0) { + mLenCnt[LoopVar1]--; + mLenCnt[LoopVar1 + 1] += 2; + break; + } + } + + Cum--; + } + + for (LoopVar1 = 16; LoopVar1 > 0; LoopVar1--) { + LoopVar2 = mLenCnt[LoopVar1]; + LoopVar2--; + while (LoopVar2 >= 0) { + mLen[*mSortPtr++] = (UINT8) LoopVar1; + LoopVar2--; + } + } +} + +/** + Assign code to each symbol based on the code length array. + + @param[in] LoopVar8 The number of symbols. + @param[in] Len The code length array. + @param[out] Code The stores codes for each symbol. +**/ +VOID +MakeCode ( + IN INT32 LoopVar8, + IN UINT8 Len[ ], + OUT UINT16 Code[ ] + ) +{ + INT32 LoopVar1; + UINT16 Start[18]; + + Start[1] = 0; + for (LoopVar1 = 1; LoopVar1 <= 16; LoopVar1++) { + Start[LoopVar1 + 1] = (UINT16) ((Start[LoopVar1] + mLenCnt[LoopVar1]) << 1); + } + + for (LoopVar1 = 0; LoopVar1 < LoopVar8; LoopVar1++) { + Code[LoopVar1] = Start[Len[LoopVar1]]++; + } +} + +/** + Generates Huffman codes given a frequency distribution of symbols. + + @param[in] NParm The number of symbols. + @param[in] FreqParm The frequency of each symbol. + @param[out] LenParm The code length for each symbol. + @param[out] CodeParm The code for each symbol. + + @return The root of the Huffman tree. +**/ +INT32 +MakeTree ( + IN INT32 NParm, + IN UINT16 FreqParm[ ], + OUT UINT8 LenParm[ ], + OUT UINT16 CodeParm[ ] + ) +{ + INT32 LoopVar1; + + INT32 LoopVar2; + + INT32 LoopVar3; + + INT32 Avail; + + // + // make tree, calculate len[], return root + // + mTempInt32 = NParm; + mFreq = FreqParm; + mLen = LenParm; + Avail = mTempInt32; + mHeapSize = 0; + mHeap[1] = 0; + for (LoopVar1 = 0; LoopVar1 < mTempInt32; LoopVar1++) { + mLen[LoopVar1] = 0; + if ((mFreq[LoopVar1]) != 0) { + mHeapSize++; + mHeap[mHeapSize] = (INT16) LoopVar1; + } + } + + if (mHeapSize < 2) { + CodeParm[mHeap[1]] = 0; + return mHeap[1]; + } + + for (LoopVar1 = mHeapSize / 2; LoopVar1 >= 1; LoopVar1--) { + // + // make priority queue + // + DownHeap (LoopVar1); + } + + mSortPtr = CodeParm; + do { + LoopVar1 = mHeap[1]; + if (LoopVar1 < mTempInt32) { + *mSortPtr++ = (UINT16) LoopVar1; + } + + mHeap[1] = mHeap[mHeapSize--]; + DownHeap (1); + LoopVar2 = mHeap[1]; + if (LoopVar2 < mTempInt32) { + *mSortPtr++ = (UINT16) LoopVar2; + } + + LoopVar3 = Avail++; + mFreq[LoopVar3] = (UINT16) (mFreq[LoopVar1] + mFreq[LoopVar2]); + mHeap[1] = (INT16) LoopVar3; + DownHeap (1); + mLeft[LoopVar3] = (UINT16) LoopVar1; + mRight[LoopVar3] = (UINT16) LoopVar2; + } while (mHeapSize > 1); + + mSortPtr = CodeParm; + MakeLen (LoopVar3); + MakeCode (NParm, LenParm, CodeParm); + + // + // return root + // + return LoopVar3; +} + +/** + Outputs rightmost LoopVar8 bits of x + + @param[in] LoopVar8 The rightmost LoopVar8 bits of the data is used. + @param[in] x The data. +**/ +VOID +PutBits ( + IN INT32 LoopVar8, + IN UINT32 x + ) +{ + UINT8 Temp; + + if (LoopVar8 < mBitCount) { + mSubBitBuf |= x << (mBitCount -= LoopVar8); + } else { + + Temp = (UINT8)(mSubBitBuf | (x >> (LoopVar8 -= mBitCount))); + if (mDst < mDstUpperLimit) { + *mDst++ = Temp; + } + mCompSize++; + + if (LoopVar8 < UINT8_BIT) { + mSubBitBuf = x << (mBitCount = UINT8_BIT - LoopVar8); + } else { + + Temp = (UINT8)(x >> (LoopVar8 - UINT8_BIT)); + if (mDst < mDstUpperLimit) { + *mDst++ = Temp; + } + mCompSize++; + + mSubBitBuf = x << (mBitCount = 2 * UINT8_BIT - LoopVar8); + } + } +} + +/** + Encode a signed 32 bit number. + + @param[in] LoopVar5 The number to encode. +**/ +VOID +EncodeC ( + IN INT32 LoopVar5 + ) +{ + PutBits (mCLen[LoopVar5], mCCode[LoopVar5]); +} + +/** + Encode a unsigned 32 bit number. + + @param[in] LoopVar7 The number to encode. +**/ +VOID +EncodeP ( + IN UINT32 LoopVar7 + ) +{ + UINT32 LoopVar5; + + UINT32 LoopVar6; + + LoopVar5 = 0; + LoopVar6 = LoopVar7; + while (LoopVar6 != 0) { + LoopVar6 >>= 1; + LoopVar5++; + } + + PutBits (mPTLen[LoopVar5], mPTCode[LoopVar5]); + if (LoopVar5 > 1) { + PutBits(LoopVar5 - 1, LoopVar7 & (0xFFFFU >> (17 - LoopVar5))); + } +} + +/** + Count the frequencies for the Extra Set. + +**/ +VOID +CountTFreq ( + VOID + ) +{ + INT32 LoopVar1; + + INT32 LoopVar3; + + INT32 LoopVar8; + + INT32 Count; + + for (LoopVar1 = 0; LoopVar1 < NT; LoopVar1++) { + mTFreq[LoopVar1] = 0; + } + + LoopVar8 = NC; + while (LoopVar8 > 0 && mCLen[LoopVar8 - 1] == 0) { + LoopVar8--; + } + + LoopVar1 = 0; + while (LoopVar1 < LoopVar8) { + LoopVar3 = mCLen[LoopVar1++]; + if (LoopVar3 == 0) { + Count = 1; + while (LoopVar1 < LoopVar8 && mCLen[LoopVar1] == 0) { + LoopVar1++; + Count++; + } + + if (Count <= 2) { + mTFreq[0] = (UINT16) (mTFreq[0] + Count); + } else if (Count <= 18) { + mTFreq[1]++; + } else if (Count == 19) { + mTFreq[0]++; + mTFreq[1]++; + } else { + mTFreq[2]++; + } + } else { + ASSERT((LoopVar3+2)<(2 * NT - 1)); + mTFreq[LoopVar3 + 2]++; + } + } +} + +/** + Outputs the code length array for the Extra Set or the Position Set. + + @param[in] LoopVar8 The number of symbols. + @param[in] nbit The number of bits needed to represent 'LoopVar8'. + @param[in] Special The special symbol that needs to be take care of. + +**/ +VOID +WritePTLen ( + IN INT32 LoopVar8, + IN INT32 nbit, + IN INT32 Special + ) +{ + INT32 LoopVar1; + + INT32 LoopVar3; + + while (LoopVar8 > 0 && mPTLen[LoopVar8 - 1] == 0) { + LoopVar8--; + } + + PutBits (nbit, LoopVar8); + LoopVar1 = 0; + while (LoopVar1 < LoopVar8) { + LoopVar3 = mPTLen[LoopVar1++]; + if (LoopVar3 <= 6) { + PutBits (3, LoopVar3); + } else { + PutBits (LoopVar3 - 3, (1U << (LoopVar3 - 3)) - 2); + } + + if (LoopVar1 == Special) { + while (LoopVar1 < 6 && mPTLen[LoopVar1] == 0) { + LoopVar1++; + } + + PutBits (2, (LoopVar1 - 3) & 3); + } + } +} + +/** + Outputs the code length array for Char&Length Set. +**/ +VOID +WriteCLen ( + VOID + ) +{ + INT32 LoopVar1; + + INT32 LoopVar3; + + INT32 LoopVar8; + + INT32 Count; + + LoopVar8 = NC; + while (LoopVar8 > 0 && mCLen[LoopVar8 - 1] == 0) { + LoopVar8--; + } + + PutBits (CBIT, LoopVar8); + LoopVar1 = 0; + while (LoopVar1 < LoopVar8) { + LoopVar3 = mCLen[LoopVar1++]; + if (LoopVar3 == 0) { + Count = 1; + while (LoopVar1 < LoopVar8 && mCLen[LoopVar1] == 0) { + LoopVar1++; + Count++; + } + + if (Count <= 2) { + for (LoopVar3 = 0; LoopVar3 < Count; LoopVar3++) { + PutBits (mPTLen[0], mPTCode[0]); + } + } else if (Count <= 18) { + PutBits (mPTLen[1], mPTCode[1]); + PutBits (4, Count - 3); + } else if (Count == 19) { + PutBits (mPTLen[0], mPTCode[0]); + PutBits (mPTLen[1], mPTCode[1]); + PutBits (4, 15); + } else { + PutBits (mPTLen[2], mPTCode[2]); + PutBits (CBIT, Count - 20); + } + } else { + ASSERT((LoopVar3+2)= NC) { + CountTFreq (); + Root = MakeTree (NT, mTFreq, mPTLen, mPTCode); + if (Root >= NT) { + WritePTLen (NT, TBIT, 3); + } else { + PutBits (TBIT, 0); + PutBits (TBIT, Root); + } + + WriteCLen (); + } else { + PutBits (TBIT, 0); + PutBits (TBIT, 0); + PutBits (CBIT, 0); + PutBits (CBIT, Root); + } + + Root = MakeTree (NP, mPFreq, mPTLen, mPTCode); + if (Root >= NP) { + WritePTLen (NP, PBIT, -1); + } else { + PutBits (PBIT, 0); + PutBits (PBIT, Root); + } + + Pos = 0; + for (LoopVar1 = 0; LoopVar1 < Size; LoopVar1++) { + if (LoopVar1 % UINT8_BIT == 0) { + Flags = mBuf[Pos++]; + } else { + Flags <<= 1; + } + if ((Flags & (1U << (UINT8_BIT - 1))) != 0){ + EncodeC(mBuf[Pos++] + (1U << UINT8_BIT)); + LoopVar3 = mBuf[Pos++] << UINT8_BIT; + LoopVar3 += mBuf[Pos++]; + + EncodeP (LoopVar3); + } else { + EncodeC (mBuf[Pos++]); + } + } + + SetMem (mCFreq, NC * sizeof (UINT16), 0); + SetMem (mPFreq, NP * sizeof (UINT16), 0); +} + +/** + Start the huffman encoding. + +**/ +VOID +HufEncodeStart ( + VOID + ) +{ + SetMem (mCFreq, NC * sizeof (UINT16), 0); + SetMem (mPFreq, NP * sizeof (UINT16), 0); + + mOutputPos = mOutputMask = 0; + + mBitCount = UINT8_BIT; + mSubBitBuf = 0; +} + +/** + Outputs an Original Character or a Pointer. + + @param[in] LoopVar5 The original character or the 'String Length' element of + a Pointer. + @param[in] LoopVar7 The 'Position' field of a Pointer. +**/ +VOID +CompressOutput ( + IN UINT32 LoopVar5, + IN UINT32 LoopVar7 + ) +{ + STATIC UINT32 CPos; + + if ((mOutputMask >>= 1) == 0) { + mOutputMask = 1U << (UINT8_BIT - 1); + if (mOutputPos >= mBufSiz - 3 * UINT8_BIT) { + SendBlock (); + mOutputPos = 0; + } + + CPos = mOutputPos++; + mBuf[CPos] = 0; + } + mBuf[mOutputPos++] = (UINT8) LoopVar5; + mCFreq[LoopVar5]++; + if (LoopVar5 >= (1U << UINT8_BIT)) { + mBuf[CPos] = (UINT8)(mBuf[CPos]|mOutputMask); + mBuf[mOutputPos++] = (UINT8)(LoopVar7 >> UINT8_BIT); + mBuf[mOutputPos++] = (UINT8) LoopVar7; + LoopVar5 = 0; + while (LoopVar7!=0) { + LoopVar7 >>= 1; + LoopVar5++; + } + mPFreq[LoopVar5]++; + } +} + +/** + End the huffman encoding. + +**/ +VOID +HufEncodeEnd ( + VOID + ) +{ + SendBlock (); + + // + // Flush remaining bits + // + PutBits (UINT8_BIT - 1, 0); +} + +/** + The main controlling routine for compression process. + + @retval EFI_SUCCESS The compression is successful. + @retval EFI_OUT_0F_RESOURCES Not enough memory for compression process. +**/ +EFI_STATUS +Encode ( + VOID + ) +{ + EFI_STATUS Status; + INT32 LastMatchLen; + NODE LastMatchPos; + + Status = AllocateMemory (); + if (EFI_ERROR (Status)) { + FreeMemory (); + return Status; + } + + InitSlide (); + + HufEncodeStart (); + + mRemainder = FreadCrc (&mText[WNDSIZ], WNDSIZ + MAXMATCH); + + mMatchLen = 0; + mPos = WNDSIZ; + InsertNode (); + if (mMatchLen > mRemainder) { + mMatchLen = mRemainder; + } + + while (mRemainder > 0) { + LastMatchLen = mMatchLen; + LastMatchPos = mMatchPos; + if (!GetNextMatch ()) { + Status = EFI_OUT_OF_RESOURCES; + } + if (mMatchLen > mRemainder) { + mMatchLen = mRemainder; + } + + if (mMatchLen > LastMatchLen || LastMatchLen < THRESHOLD) { + // + // Not enough benefits are gained by outputting a pointer, + // so just output the original character + // + CompressOutput(mText[mPos - 1], 0); + } else { + // + // Outputting a pointer is beneficial enough, do it. + // + + CompressOutput(LastMatchLen + (UINT8_MAX + 1 - THRESHOLD), + (mPos - LastMatchPos - 2) & (WNDSIZ - 1)); + LastMatchLen--; + while (LastMatchLen > 0) { + if (!GetNextMatch ()) { + Status = EFI_OUT_OF_RESOURCES; + } + LastMatchLen--; + } + + if (mMatchLen > mRemainder) { + mMatchLen = mRemainder; + } + } + } + + HufEncodeEnd (); + FreeMemory (); + return (Status); +} + +/** + The compression routine. + + @param[in] SrcBuffer The buffer containing the source data. + @param[in] SrcSize Number of bytes in SrcBuffer. + @param[in] DstBuffer The buffer to put the compressed image in. + @param[in, out] DstSize On input the size (in bytes) of DstBuffer, on + return the number of bytes placed in DstBuffer. + + @retval EFI_SUCCESS The compression was sucessful. + @retval EFI_BUFFER_TOO_SMALL The buffer was too small. DstSize is required. +**/ +EFI_STATUS +Compress ( + IN VOID *SrcBuffer, + IN UINT64 SrcSize, + IN VOID *DstBuffer, + IN OUT UINT64 *DstSize + ) +{ + EFI_STATUS Status; + + // + // Initializations + // + mBufSiz = 0; + mBuf = NULL; + mText = NULL; + mLevel = NULL; + mChildCount = NULL; + mPosition = NULL; + mParent = NULL; + mPrev = NULL; + mNext = NULL; + + mSrc = SrcBuffer; + mSrcUpperLimit = mSrc + SrcSize; + mDst = DstBuffer; + mDstUpperLimit = mDst +*DstSize; + + PutDword (0L); + PutDword (0L); + + MakeCrcTable (); + + mOrigSize = mCompSize = 0; + mCrc = INIT_CRC; + + // + // Compress it + // + Status = Encode (); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + // + // Null terminate the compressed data + // + if (mDst < mDstUpperLimit) { + *mDst++ = 0; + } + // + // Fill in compressed size and original size + // + mDst = DstBuffer; + PutDword (mCompSize + 1); + PutDword (mOrigSize); + + // + // Return + // + if (mCompSize + 1 + 8 > *DstSize) { + *DstSize = mCompSize + 1 + 8; + return EFI_BUFFER_TOO_SMALL; + } else { + *DstSize = mCompSize + 1 + 8; + return EFI_SUCCESS; + } + +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Compress.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Compress.h new file mode 100644 index 00000000..150c538e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Compress.h @@ -0,0 +1,33 @@ +/** @file + Header file for compression routine. + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_SHELL_COMPRESS_H_ +#define _EFI_SHELL_COMPRESS_H_ + +/** + The compression routine. + + @param[in] SrcBuffer The buffer containing the source data. + @param[in] SrcSize Number of bytes in SrcBuffer. + @param[in] DstBuffer The buffer to put the compressed image in. + @param[in, out] DstSize On input the size (in bytes) of DstBuffer, on + return the number of bytes placed in DstBuffer. + + @retval EFI_SUCCESS The compression was sucessful. + @retval EFI_BUFFER_TOO_SMALL The buffer was too small. DstSize is required. +**/ +EFI_STATUS +Compress ( + IN VOID *SrcBuffer, + IN UINT64 SrcSize, + IN VOID *DstBuffer, + IN OUT UINT64 *DstSize + ); + +#endif + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Dblk.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Dblk.c new file mode 100644 index 00000000..8fc876d0 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Dblk.c @@ -0,0 +1,201 @@ +/** @file + Main file for Dblk shell Debug1 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDebug1CommandsLib.h" +#include + +/** + Display blocks to the screen. + + @param[in] DevPath The device path to get the blocks from. + @param[in] Lba The Lba number to start from. + @param[in] BlockCount How many blocks to display. + + @retval SHELL_SUCCESS The display was successful. +**/ +SHELL_STATUS +DisplayTheBlocks( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevPath, + IN CONST UINT64 Lba, + IN CONST UINT8 BlockCount + ) +{ + EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_HANDLE BlockIoHandle; + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + UINT8 *Buffer; + UINT8 *OriginalBuffer; + UINTN BufferSize; + + ShellStatus = SHELL_SUCCESS; + + Status = gBS->LocateDevicePath(&gEfiBlockIoProtocolGuid, (EFI_DEVICE_PATH_PROTOCOL **)&DevPath, &BlockIoHandle); + if (EFI_ERROR(Status)) { + return (SHELL_NOT_FOUND); + } + + Status = gBS->OpenProtocol(BlockIoHandle, &gEfiBlockIoProtocolGuid, (VOID**)&BlockIo, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(Status)) { + return (SHELL_NOT_FOUND); + } + + BufferSize = BlockIo->Media->BlockSize * BlockCount; + if(BlockIo->Media->IoAlign == 0) { + BlockIo->Media->IoAlign = 1; + } + + if (BufferSize > 0) { + OriginalBuffer = AllocateZeroPool(BufferSize + BlockIo->Media->IoAlign); + Buffer = ALIGN_POINTER (OriginalBuffer,BlockIo->Media->IoAlign); + } else { + ShellPrintEx(-1,-1,L" BlockSize: 0x%08x, BlockCount: 0x%08x\r\n", BlockIo->Media->BlockSize, BlockCount); + OriginalBuffer = NULL; + Buffer = NULL; + } + + Status = BlockIo->ReadBlocks(BlockIo, BlockIo->Media->MediaId, Lba, BufferSize, Buffer); + if (!EFI_ERROR(Status) && Buffer != NULL) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DBLK_HEADER), + gShellDebug1HiiHandle, + Lba, + BufferSize, + BlockIo + ); + + DumpHex(2,0,BufferSize,Buffer); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_FILE_READ_FAIL), gShellDebug1HiiHandle, L"dblk", L"BlockIo"); + ShellStatus = SHELL_DEVICE_ERROR; + } + + if (OriginalBuffer != NULL) { + FreePool (OriginalBuffer); + } + + gBS->CloseProtocol(BlockIoHandle, &gEfiBlockIoProtocolGuid, gImageHandle, NULL); + return (ShellStatus); +} + +/** + Function for 'dblk' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunDblk ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CONST CHAR16 *BlockName; + CONST CHAR16 *LbaString; + CONST CHAR16 *BlockCountString; + UINT64 Lba; + UINT64 BlockCount; + EFI_DEVICE_PATH_PROTOCOL *DevPath; + + ShellStatus = SHELL_SUCCESS; + Status = EFI_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"dblk", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetCount(Package) > 4) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"dblk"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetCount(Package) < 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"dblk"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // Parse the params + // + BlockName = ShellCommandLineGetRawValue(Package, 1); + LbaString = ShellCommandLineGetRawValue(Package, 2); + BlockCountString = ShellCommandLineGetRawValue(Package, 3); + + if (LbaString == NULL) { + Lba = 0; + } else { + if (!ShellIsHexOrDecimalNumber(LbaString, TRUE, FALSE)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"dblk", LbaString); + ShellStatus = SHELL_INVALID_PARAMETER; + } + ShellConvertStringToUint64(LbaString, &Lba, TRUE, FALSE); + } + + if (BlockCountString == NULL) { + BlockCount = 1; + } else { + if (!ShellIsHexOrDecimalNumber(BlockCountString, TRUE, FALSE)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"dblk", BlockCountString); + ShellStatus = SHELL_INVALID_PARAMETER; + } + ShellConvertStringToUint64(BlockCountString, &BlockCount, TRUE, FALSE); + if (BlockCount > 0x10) { + BlockCount = 0x10; + } else if (BlockCount == 0) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"dblk", BlockCountString); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } + + if (ShellStatus == SHELL_SUCCESS) { + // + // do the work if we have a valid block identifier + // + if (gEfiShellProtocol->GetDevicePathFromMap(BlockName) == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"dblk", BlockName); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + DevPath = (EFI_DEVICE_PATH_PROTOCOL*)gEfiShellProtocol->GetDevicePathFromMap(BlockName); + if (gBS->LocateDevicePath(&gEfiBlockIoProtocolGuid, &DevPath, NULL) == EFI_NOT_FOUND) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MAP_PROTOCOL), gShellDebug1HiiHandle, L"dblk", BlockName, L"BlockIo"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ShellStatus = DisplayTheBlocks(gEfiShellProtocol->GetDevicePathFromMap(BlockName), Lba, (UINT8)BlockCount); + } + } + } + } + + ShellCommandLineFreeVarList (Package); + } + return (ShellStatus); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Dmem.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Dmem.c new file mode 100644 index 00000000..ecba00b1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Dmem.c @@ -0,0 +1,222 @@ +/** @file + Main file for Dmem shell Debug1 function. + + Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDebug1CommandsLib.h" +#include +#include +#include +#include + +/** + Make a printable character. + + If Char is printable then return it, otherwise return a question mark. + + @param[in] Char The character to make printable. + + @return A printable character representing Char. +**/ +CHAR16 +MakePrintable( + IN CONST CHAR16 Char + ) +{ + if ((Char < 0x20 && Char > 0)||(Char > 126)) { + return (L'?'); + } + return (Char); +} + +/** + Display some Memory-Mapped-IO memory. + + @param[in] Address The starting address to display. + @param[in] Size The length of memory to display. +**/ +SHELL_STATUS +DisplayMmioMemory( + IN CONST VOID *Address, + IN CONST UINTN Size + ) +{ + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRbIo; + EFI_STATUS Status; + VOID *Buffer; + SHELL_STATUS ShellStatus; + + ShellStatus = SHELL_SUCCESS; + + Status = gBS->LocateProtocol(&gEfiPciRootBridgeIoProtocolGuid, NULL, (VOID**)&PciRbIo); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PCIRBIO_NF), gShellDebug1HiiHandle, L"dmem"); + return (SHELL_NOT_FOUND); + } + Buffer = AllocateZeroPool(Size); + if (Buffer == NULL) { + return SHELL_OUT_OF_RESOURCES; + } + + Status = PciRbIo->Mem.Read(PciRbIo, EfiPciWidthUint8, (UINT64)(UINTN)Address, Size, Buffer); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PCIRBIO_ER), gShellDebug1HiiHandle, L"dmem"); + ShellStatus = SHELL_NOT_FOUND; + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_DMEM_MMIO_HEADER_ROW), gShellDebug1HiiHandle, (UINT64)(UINTN)Address, Size); + DumpHex(2, (UINTN)Address, Size, Buffer); + } + + FreePool(Buffer); + return (ShellStatus); +} + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-mmio", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'dmem' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunDmem ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + VOID *Address; + UINT64 Size; + CONST CHAR16 *Temp1; + UINT64 AcpiTableAddress; + UINT64 Acpi20TableAddress; + UINT64 SalTableAddress; + UINT64 SmbiosTableAddress; + UINT64 MpsTableAddress; + UINTN TableWalker; + + ShellStatus = SHELL_SUCCESS; + Status = EFI_SUCCESS; + Address = NULL; + Size = 0; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"dmem", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetCount(Package) > 3) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"dmem"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Temp1 = ShellCommandLineGetRawValue(Package, 1); + if (Temp1 == NULL) { + Address = gST; + Size = sizeof (*gST); + } else { + if (!ShellIsHexOrDecimalNumber(Temp1, TRUE, FALSE) || EFI_ERROR(ShellConvertStringToUint64(Temp1, (UINT64*)&Address, TRUE, FALSE))) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"dmem", Temp1); + ShellStatus = SHELL_INVALID_PARAMETER; + } + Temp1 = ShellCommandLineGetRawValue(Package, 2); + if (Temp1 == NULL) { + Size = 512; + } else { + if (!ShellIsHexOrDecimalNumber(Temp1, FALSE, FALSE) || EFI_ERROR(ShellConvertStringToUint64(Temp1, &Size, TRUE, FALSE))) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"dmem", Temp1); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } + } + } + + if (ShellStatus == SHELL_SUCCESS) { + if (!ShellCommandLineGetFlag(Package, L"-mmio")) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_DMEM_HEADER_ROW), gShellDebug1HiiHandle, (UINT64)(UINTN)Address, Size); + DumpHex(2, (UINTN)Address, (UINTN)Size, Address); + if (Address == (VOID*)gST) { + Acpi20TableAddress = 0; + AcpiTableAddress = 0; + SalTableAddress = 0; + SmbiosTableAddress = 0; + MpsTableAddress = 0; + for (TableWalker = 0 ; TableWalker < gST->NumberOfTableEntries ; TableWalker++) { + if (CompareGuid(&gST->ConfigurationTable[TableWalker].VendorGuid, &gEfiAcpi20TableGuid)) { + Acpi20TableAddress = (UINT64)(UINTN)gST->ConfigurationTable[TableWalker].VendorTable; + continue; + } + if (CompareGuid(&gST->ConfigurationTable[TableWalker].VendorGuid, &gEfiAcpi10TableGuid)) { + AcpiTableAddress = (UINT64)(UINTN)gST->ConfigurationTable[TableWalker].VendorTable; + continue; + } + if (CompareGuid(&gST->ConfigurationTable[TableWalker].VendorGuid, &gEfiSmbiosTableGuid)) { + SmbiosTableAddress = (UINT64)(UINTN)gST->ConfigurationTable[TableWalker].VendorTable; + continue; + } + if (CompareGuid (&gST->ConfigurationTable[TableWalker].VendorGuid, &gEfiSmbios3TableGuid)) { + SmbiosTableAddress = (UINT64) (UINTN) gST->ConfigurationTable[TableWalker].VendorTable; + continue; + } + if (CompareGuid(&gST->ConfigurationTable[TableWalker].VendorGuid, &gEfiMpsTableGuid)) { + MpsTableAddress = (UINT64)(UINTN)gST->ConfigurationTable[TableWalker].VendorTable; + continue; + } + } + + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_DMEM_SYSTEM_TABLE), gShellDebug1HiiHandle, + (UINT64)(UINTN)Address, + gST->Hdr.HeaderSize, + gST->Hdr.Revision, + (UINT64)(UINTN)gST->ConIn, + (UINT64)(UINTN)gST->ConOut, + (UINT64)(UINTN)gST->StdErr, + (UINT64)(UINTN)gST->RuntimeServices, + (UINT64)(UINTN)gST->BootServices, + SalTableAddress, + AcpiTableAddress, + Acpi20TableAddress, + MpsTableAddress, + SmbiosTableAddress + ); + } + } else { + ShellStatus = DisplayMmioMemory(Address, (UINTN)Size); + } + } + + + ShellCommandLineFreeVarList (Package); + } + + return (ShellStatus); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/DmpStore.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/DmpStore.c new file mode 100644 index 00000000..d96c71e4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/DmpStore.c @@ -0,0 +1,859 @@ +/** @file + Main file for DmpStore shell Debug1 function. + + (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDebug1CommandsLib.h" + +typedef enum { + DmpStoreDisplay, + DmpStoreDelete, + DmpStoreSave, + DmpStoreLoad +} DMP_STORE_TYPE; + +typedef struct { + UINT32 Signature; + CHAR16 *Name; + EFI_GUID Guid; + UINT32 Attributes; + UINT32 DataSize; + UINT8 *Data; + LIST_ENTRY Link; +} DMP_STORE_VARIABLE; + +#define DMP_STORE_VARIABLE_SIGNATURE SIGNATURE_32 ('_', 'd', 's', 's') + +/** + Base on the input attribute value to return the attribute string. + + @param[in] Atts The input attribute value + + @retval The attribute string info. +**/ +CHAR16 * +GetAttrType ( + IN CONST UINT32 Atts + ) +{ + UINTN BufLen; + CHAR16 *RetString; + + BufLen = 0; + RetString = NULL; + + if ((Atts & EFI_VARIABLE_NON_VOLATILE) != 0) { + StrnCatGrow (&RetString, &BufLen, L"+NV", 0); + } + if ((Atts & EFI_VARIABLE_RUNTIME_ACCESS) != 0) { + StrnCatGrow (&RetString, &BufLen, L"+RT+BS", 0); + } else if ((Atts & EFI_VARIABLE_BOOTSERVICE_ACCESS) != 0) { + StrnCatGrow (&RetString, &BufLen, L"+BS", 0); + } + if ((Atts & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) { + StrnCatGrow (&RetString, &BufLen, L"+HR", 0); + } + if ((Atts & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) { + StrnCatGrow (&RetString, &BufLen, L"+AW", 0); + } + if ((Atts & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) { + StrnCatGrow (&RetString, &BufLen, L"+AT", 0); + } + + if (RetString == NULL) { + RetString = StrnCatGrow(&RetString, &BufLen, L"Invalid", 0); + } + + if ((RetString != NULL) && (RetString[0] == L'+')) { + CopyMem(RetString, RetString + 1, StrSize(RetString + 1)); + } + + return RetString; +} + +/** + Convert binary to hex format string. + + @param[in] Buffer The binary data. + @param[in] BufferSize The size in bytes of the binary data. + @param[in, out] HexString Hex format string. + @param[in] HexStringSize The size in bytes of the string. + + @return The hex format string. +**/ +CHAR16* +BinaryToHexString ( + IN VOID *Buffer, + IN UINTN BufferSize, + IN OUT CHAR16 *HexString, + IN UINTN HexStringSize + ) +{ + UINTN Index; + UINTN StringIndex; + + ASSERT (Buffer != NULL); + ASSERT ((BufferSize * 2 + 1) * sizeof (CHAR16) <= HexStringSize); + + for (Index = 0, StringIndex = 0; Index < BufferSize; Index += 1) { + StringIndex += + UnicodeSPrint ( + &HexString[StringIndex], + HexStringSize - StringIndex * sizeof (CHAR16), + L"%02x", + ((UINT8 *) Buffer)[Index] + ); + } + return HexString; +} + +/** + Load the variable data from file and set to variable data base. + + @param[in] FileHandle The file to be read. + @param[in] Name The name of the variables to be loaded. + @param[in] Guid The guid of the variables to be loaded. + @param[out] Found TRUE when at least one variable was loaded and set. + + @retval SHELL_DEVICE_ERROR Cannot access the file. + @retval SHELL_VOLUME_CORRUPTED The file is in bad format. + @retval SHELL_OUT_OF_RESOURCES There is not enough memory to perform the operation. + @retval SHELL_SUCCESS Successfully load and set the variables. +**/ +SHELL_STATUS +LoadVariablesFromFile ( + IN SHELL_FILE_HANDLE FileHandle, + IN CONST CHAR16 *Name, + IN CONST EFI_GUID *Guid, + OUT BOOLEAN *Found + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + UINT32 NameSize; + UINT32 DataSize; + UINTN BufferSize; + UINTN RemainingSize; + UINT64 Position; + UINT64 FileSize; + LIST_ENTRY List; + DMP_STORE_VARIABLE *Variable; + LIST_ENTRY *Link; + CHAR16 *Attributes; + UINT8 *Buffer; + UINT32 Crc32; + + Status = ShellGetFileSize (FileHandle, &FileSize); + if (EFI_ERROR (Status)) { + return SHELL_DEVICE_ERROR; + } + + ShellStatus = SHELL_SUCCESS; + + InitializeListHead (&List); + + Position = 0; + while (Position < FileSize) { + // + // NameSize + // + BufferSize = sizeof (NameSize); + Status = ShellReadFile (FileHandle, &BufferSize, &NameSize); + if (EFI_ERROR (Status) || (BufferSize != sizeof (NameSize))) { + ShellStatus = SHELL_VOLUME_CORRUPTED; + break; + } + + // + // DataSize + // + BufferSize = sizeof (DataSize); + Status = ShellReadFile (FileHandle, &BufferSize, &DataSize); + if (EFI_ERROR (Status) || (BufferSize != sizeof (DataSize))) { + ShellStatus = SHELL_VOLUME_CORRUPTED; + break; + } + + // + // Name, Guid, Attributes, Data, Crc32 + // + RemainingSize = NameSize + sizeof (EFI_GUID) + sizeof (UINT32) + DataSize + sizeof (Crc32); + BufferSize = sizeof (NameSize) + sizeof (DataSize) + RemainingSize; + Buffer = AllocatePool (BufferSize); + if (Buffer == NULL) { + ShellStatus = SHELL_OUT_OF_RESOURCES; + break; + } + BufferSize = RemainingSize; + Status = ShellReadFile (FileHandle, &BufferSize, (UINT32 *) Buffer + 2); + if (EFI_ERROR (Status) || (BufferSize != RemainingSize)) { + ShellStatus = SHELL_VOLUME_CORRUPTED; + FreePool (Buffer); + break; + } + + // + // Check Crc32 + // + * (UINT32 *) Buffer = NameSize; + * ((UINT32 *) Buffer + 1) = DataSize; + BufferSize = RemainingSize + sizeof (NameSize) + sizeof (DataSize) - sizeof (Crc32); + gBS->CalculateCrc32 ( + Buffer, + BufferSize, + &Crc32 + ); + if (Crc32 != * (UINT32 *) (Buffer + BufferSize)) { + FreePool (Buffer); + ShellStatus = SHELL_VOLUME_CORRUPTED; + break; + } + + Position += BufferSize + sizeof (Crc32); + + Variable = AllocateZeroPool (sizeof (*Variable) + NameSize + DataSize); + if (Variable == NULL) { + FreePool (Buffer); + ShellStatus = SHELL_OUT_OF_RESOURCES; + break; + } + Variable->Signature = DMP_STORE_VARIABLE_SIGNATURE; + Variable->Name = (CHAR16 *) (Variable + 1); + Variable->DataSize = DataSize; + Variable->Data = (UINT8 *) Variable->Name + NameSize; + CopyMem (Variable->Name, Buffer + sizeof (NameSize) + sizeof (DataSize), NameSize); + CopyMem (&Variable->Guid, Buffer + sizeof (NameSize) + sizeof (DataSize) + NameSize, sizeof (EFI_GUID)); + CopyMem (&Variable->Attributes, Buffer + sizeof (NameSize) + sizeof (DataSize) + NameSize + sizeof (EFI_GUID), sizeof (UINT32)); + CopyMem (Variable->Data, Buffer + sizeof (NameSize) + sizeof (DataSize) + NameSize + sizeof (EFI_GUID) + sizeof (UINT32), DataSize); + + InsertTailList (&List, &Variable->Link); + FreePool (Buffer); + } + + if ((Position != FileSize) || (ShellStatus != SHELL_SUCCESS)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_LOAD_BAD_FILE), gShellDebug1HiiHandle, L"dmpstore"); + if (Position != FileSize) { + ShellStatus = SHELL_VOLUME_CORRUPTED; + } + } + + for ( Link = GetFirstNode (&List) + ; !IsNull (&List, Link) && (ShellStatus == SHELL_SUCCESS) + ; Link = GetNextNode (&List, Link) + ) { + Variable = CR (Link, DMP_STORE_VARIABLE, Link, DMP_STORE_VARIABLE_SIGNATURE); + + if (((Name == NULL) || gUnicodeCollation->MetaiMatch (gUnicodeCollation, Variable->Name, (CHAR16 *) Name)) && + ((Guid == NULL) || CompareGuid (&Variable->Guid, Guid)) + ) { + Attributes = GetAttrType (Variable->Attributes); + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN(STR_DMPSTORE_HEADER_LINE), gShellDebug1HiiHandle, + Attributes, &Variable->Guid, Variable->Name, Variable->DataSize + ); + SHELL_FREE_NON_NULL(Attributes); + + *Found = TRUE; + Status = gRT->SetVariable ( + Variable->Name, + &Variable->Guid, + Variable->Attributes, + Variable->DataSize, + Variable->Data + ); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_LOAD_GEN_FAIL), gShellDebug1HiiHandle, L"dmpstore", Variable->Name, Status); + } + } + } + + for (Link = GetFirstNode (&List); !IsNull (&List, Link); ) { + Variable = CR (Link, DMP_STORE_VARIABLE, Link, DMP_STORE_VARIABLE_SIGNATURE); + Link = RemoveEntryList (&Variable->Link); + FreePool (Variable); + } + + return ShellStatus; +} + +/** + Append one variable to file. + + @param[in] FileHandle The file to be appended. + @param[in] Name The variable name. + @param[in] Guid The variable GUID. + @param[in] Attributes The variable attributes. + @param[in] DataSize The variable data size. + @param[in] Data The variable data. + + @retval EFI_OUT_OF_RESOURCES There is not enough memory to perform the operation. + @retval EFI_SUCCESS The variable is appended to file successfully. + @retval others Failed to append the variable to file. +**/ +EFI_STATUS +AppendSingleVariableToFile ( + IN SHELL_FILE_HANDLE FileHandle, + IN CONST CHAR16 *Name, + IN CONST EFI_GUID *Guid, + IN UINT32 Attributes, + IN UINT32 DataSize, + IN CONST UINT8 *Data + ) +{ + UINT32 NameSize; + UINT8 *Buffer; + UINT8 *Ptr; + UINTN BufferSize; + EFI_STATUS Status; + + NameSize = (UINT32) StrSize (Name); + BufferSize = sizeof (NameSize) + sizeof (DataSize) + + sizeof (*Guid) + + sizeof (Attributes) + + NameSize + DataSize + + sizeof (UINT32); + + Buffer = AllocatePool (BufferSize); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Ptr = Buffer; + // + // NameSize and DataSize + // + * (UINT32 *) Ptr = NameSize; + Ptr += sizeof (NameSize); + *(UINT32 *) Ptr = DataSize; + Ptr += sizeof (DataSize); + + // + // Name + // + CopyMem (Ptr, Name, NameSize); + Ptr += NameSize; + + // + // Guid + // + CopyMem (Ptr, Guid, sizeof (*Guid)); + Ptr += sizeof (*Guid); + + // + // Attributes + // + * (UINT32 *) Ptr = Attributes; + Ptr += sizeof (Attributes); + + // + // Data + // + CopyMem (Ptr, Data, DataSize); + Ptr += DataSize; + + // + // Crc32 + // + gBS->CalculateCrc32 (Buffer, (UINTN) Ptr - (UINTN) Buffer, (UINT32 *) Ptr); + + Status = ShellWriteFile (FileHandle, &BufferSize, Buffer); + FreePool (Buffer); + + if (!EFI_ERROR (Status) && + (BufferSize != sizeof (NameSize) + sizeof (DataSize) + sizeof (*Guid) + sizeof (Attributes) + NameSize + DataSize + sizeof (UINT32)) + ) { + Status = EFI_DEVICE_ERROR; + } + + return Status; +} + +/** + Recursive function to display or delete variables. + + This function will call itself to create a stack-based list of allt he variables to process, + then fromt he last to the first, they will do either printing or deleting. + + This is necessary since once a delete happens GetNextVariableName() will work. + + @param[in] Name The variable name of the EFI variable (or NULL). + @param[in] Guid The GUID of the variable set (or NULL). + @param[in] Type The operation type. + @param[in] FileHandle The file to operate on (or NULL). + @param[in] PrevName The previous variable name from GetNextVariableName. L"" to start. + @param[in] FoundVarGuid The previous GUID from GetNextVariableName. ignored at start. + @param[in] FoundOne If a VariableName or Guid was specified and one was printed or + deleted, then set this to TRUE, otherwise ignored. + @param[in] StandardFormatOutput TRUE indicates Standard-Format Output. + + @retval SHELL_SUCCESS The operation was successful. + @retval SHELL_OUT_OF_RESOURCES A memorty allocation failed. + @retval SHELL_ABORTED The abort message was received. + @retval SHELL_DEVICE_ERROR UEFI Variable Services returned an error. + @retval SHELL_NOT_FOUND the Name/Guid pair could not be found. +**/ +SHELL_STATUS +CascadeProcessVariables ( + IN CONST CHAR16 *Name OPTIONAL, + IN CONST EFI_GUID *Guid OPTIONAL, + IN DMP_STORE_TYPE Type, + IN EFI_FILE_PROTOCOL *FileHandle OPTIONAL, + IN CONST CHAR16 * CONST PrevName, + IN EFI_GUID FoundVarGuid, + IN BOOLEAN *FoundOne, + IN BOOLEAN StandardFormatOutput + ) +{ + EFI_STATUS Status; + CHAR16 *FoundVarName; + UINT8 *DataBuffer; + UINTN DataSize; + UINT32 Atts; + SHELL_STATUS ShellStatus; + UINTN NameSize; + CHAR16 *AttrString; + CHAR16 *HexString; + EFI_STATUS SetStatus; + CONST CHAR16 *GuidName; + + if (ShellGetExecutionBreakFlag()) { + return (SHELL_ABORTED); + } + + NameSize = 0; + FoundVarName = NULL; + + if (PrevName!=NULL) { + StrnCatGrow(&FoundVarName, &NameSize, PrevName, 0); + } else { + FoundVarName = AllocateZeroPool(sizeof(CHAR16)); + NameSize = sizeof(CHAR16); + } + + Status = gRT->GetNextVariableName (&NameSize, FoundVarName, &FoundVarGuid); + if (Status == EFI_BUFFER_TOO_SMALL) { + SHELL_FREE_NON_NULL(FoundVarName); + FoundVarName = AllocateZeroPool (NameSize); + if (FoundVarName != NULL) { + if (PrevName != NULL) { + StrnCpyS(FoundVarName, NameSize/sizeof(CHAR16), PrevName, NameSize/sizeof(CHAR16) - 1); + } + + Status = gRT->GetNextVariableName (&NameSize, FoundVarName, &FoundVarGuid); + } else { + Status = EFI_OUT_OF_RESOURCES; + } + } + + // + // No more is fine. + // + if (Status == EFI_NOT_FOUND) { + SHELL_FREE_NON_NULL(FoundVarName); + return (SHELL_SUCCESS); + } else if (EFI_ERROR(Status)) { + SHELL_FREE_NON_NULL(FoundVarName); + return (SHELL_DEVICE_ERROR); + } + + // + // Recurse to the next iteration. We know "our" variable's name. + // + ShellStatus = CascadeProcessVariables (Name, Guid, Type, FileHandle, FoundVarName, FoundVarGuid, FoundOne, StandardFormatOutput); + + if (ShellGetExecutionBreakFlag() || (ShellStatus == SHELL_ABORTED)) { + SHELL_FREE_NON_NULL(FoundVarName); + return (SHELL_ABORTED); + } + + // + // No matter what happened we process our own variable + // Only continue if Guid and VariableName are each either NULL or a match + // + if ( ( Name == NULL + || gUnicodeCollation->MetaiMatch(gUnicodeCollation, FoundVarName, (CHAR16*) Name) ) + && ( Guid == NULL + || CompareGuid(&FoundVarGuid, Guid) ) + ) { + DataSize = 0; + DataBuffer = NULL; + // + // do the print or delete + // + *FoundOne = TRUE; + Status = gRT->GetVariable (FoundVarName, &FoundVarGuid, &Atts, &DataSize, DataBuffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + SHELL_FREE_NON_NULL (DataBuffer); + DataBuffer = AllocatePool (DataSize); + if (DataBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + Status = gRT->GetVariable (FoundVarName, &FoundVarGuid, &Atts, &DataSize, DataBuffer); + } + } + // + // Last error check then print this variable out. + // + if (Type == DmpStoreDisplay) { + if (!EFI_ERROR(Status) && (DataBuffer != NULL) && (FoundVarName != NULL)) { + AttrString = GetAttrType(Atts); + if (StandardFormatOutput) { + HexString = AllocatePool ((DataSize * 2 + 1) * sizeof (CHAR16)); + if (HexString != NULL) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_VAR_SFO), gShellDebug1HiiHandle, + FoundVarName, &FoundVarGuid, Atts, DataSize, + BinaryToHexString ( + DataBuffer, DataSize, HexString, (DataSize * 2 + 1) * sizeof (CHAR16) + ) + ); + FreePool (HexString); + } else { + Status = EFI_OUT_OF_RESOURCES; + } + } else { + Status = gEfiShellProtocol->GetGuidName(&FoundVarGuid, &GuidName); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_HEADER_LINE), gShellDebug1HiiHandle, + AttrString, &FoundVarGuid, FoundVarName, DataSize + ); + } else { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_HEADER_LINE2), gShellDebug1HiiHandle, + AttrString, GuidName, FoundVarName, DataSize + ); + } + DumpHex (2, 0, DataSize, DataBuffer); + } + SHELL_FREE_NON_NULL (AttrString); + } + } else if (Type == DmpStoreSave) { + if (!EFI_ERROR(Status) && (DataBuffer != NULL) && (FoundVarName != NULL)) { + AttrString = GetAttrType (Atts); + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_HEADER_LINE), gShellDebug1HiiHandle, + AttrString, &FoundVarGuid, FoundVarName, DataSize + ); + Status = AppendSingleVariableToFile ( + FileHandle, + FoundVarName, + &FoundVarGuid, + Atts, + (UINT32) DataSize, + DataBuffer + ); + SHELL_FREE_NON_NULL (AttrString); + } + } else if (Type == DmpStoreDelete) { + // + // We only need name to delete it... + // + SetStatus = gRT->SetVariable (FoundVarName, &FoundVarGuid, Atts, 0, NULL); + if (StandardFormatOutput) { + if (SetStatus == EFI_SUCCESS) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_NO_VAR_FOUND_NG_SFO), gShellDebug1HiiHandle, + FoundVarName, &FoundVarGuid + ); + } + } else { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_DELETE_LINE), gShellDebug1HiiHandle, + &FoundVarGuid, FoundVarName, SetStatus + ); + } + } + SHELL_FREE_NON_NULL(DataBuffer); + } + + SHELL_FREE_NON_NULL(FoundVarName); + + if (Status == EFI_DEVICE_ERROR) { + ShellStatus = SHELL_DEVICE_ERROR; + } else if (Status == EFI_SECURITY_VIOLATION) { + ShellStatus = SHELL_SECURITY_VIOLATION; + } else if (EFI_ERROR(Status)) { + ShellStatus = SHELL_NOT_READY; + } + + return (ShellStatus); +} + +/** + Function to display or delete variables. This will set up and call into the recursive function. + + @param[in] Name The variable name of the EFI variable (or NULL). + @param[in] Guid The GUID of the variable set (or NULL). + @param[in] Type The operation type. + @param[in] FileHandle The file to save or load variables. + @param[in] StandardFormatOutput TRUE indicates Standard-Format Output. + + @retval SHELL_SUCCESS The operation was successful. + @retval SHELL_OUT_OF_RESOURCES A memorty allocation failed. + @retval SHELL_ABORTED The abort message was received. + @retval SHELL_DEVICE_ERROR UEFI Variable Services returned an error. + @retval SHELL_NOT_FOUND the Name/Guid pair could not be found. +**/ +SHELL_STATUS +ProcessVariables ( + IN CONST CHAR16 *Name OPTIONAL, + IN CONST EFI_GUID *Guid OPTIONAL, + IN DMP_STORE_TYPE Type, + IN SHELL_FILE_HANDLE FileHandle OPTIONAL, + IN BOOLEAN StandardFormatOutput + ) +{ + SHELL_STATUS ShellStatus; + BOOLEAN Found; + EFI_GUID FoundVarGuid; + + Found = FALSE; + ShellStatus = SHELL_SUCCESS; + ZeroMem (&FoundVarGuid, sizeof(EFI_GUID)); + + if (StandardFormatOutput) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_GEN_SFO_HEADER), gShellDebug1HiiHandle, L"dmpstore"); + } + + if (Type == DmpStoreLoad) { + ShellStatus = LoadVariablesFromFile (FileHandle, Name, Guid, &Found); + } else { + ShellStatus = CascadeProcessVariables (Name, Guid, Type, FileHandle, NULL, FoundVarGuid, &Found, StandardFormatOutput); + } + + if (!Found) { + if (ShellStatus == SHELL_OUT_OF_RESOURCES) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellDebug1HiiHandle, L"dmpstore"); + return (ShellStatus); + } else if (Name != NULL && Guid == NULL) { + if (StandardFormatOutput) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_NO_VAR_FOUND_N_SFO), gShellDebug1HiiHandle, Name); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_NO_VAR_FOUND_N), gShellDebug1HiiHandle, L"dmpstore", Name); + } + } else if (Name != NULL && Guid != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_NO_VAR_FOUND_GN), gShellDebug1HiiHandle, L"dmpstore", Guid, Name); + } else if (Name == NULL && Guid == NULL) { + if (StandardFormatOutput) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_NO_VAR_FOUND_SFO), gShellDebug1HiiHandle); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_NO_VAR_FOUND), gShellDebug1HiiHandle, L"dmpstore"); + } + } else if (Name == NULL && Guid != NULL) { + if (StandardFormatOutput) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_NO_VAR_FOUND_G_SFO), gShellDebug1HiiHandle, Guid); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_NO_VAR_FOUND_G), gShellDebug1HiiHandle, L"dmpstore", Guid); + } + } + return (SHELL_NOT_FOUND); + } + return (ShellStatus); +} + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-d", TypeFlag}, + {L"-l", TypeValue}, + {L"-s", TypeValue}, + {L"-all", TypeFlag}, + {L"-guid", TypeValue}, + {L"-sfo", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'dmpstore' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunDmpStore ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + RETURN_STATUS RStatus; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CONST CHAR16 *GuidStr; + CONST CHAR16 *File; + EFI_GUID *Guid; + EFI_GUID GuidData; + CONST CHAR16 *Name; + DMP_STORE_TYPE Type; + SHELL_FILE_HANDLE FileHandle; + EFI_FILE_INFO *FileInfo; + BOOLEAN StandardFormatOutput; + + ShellStatus = SHELL_SUCCESS; + Package = NULL; + FileHandle = NULL; + File = NULL; + Type = DmpStoreDisplay; + StandardFormatOutput = FALSE; + + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"dmpstore", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetCount(Package) > 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"dmpstore"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetFlag(Package, L"-all") && ShellCommandLineGetFlag(Package, L"-guid")) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CONFLICT), gShellDebug1HiiHandle, L"dmpstore", L"-all", L"-guid"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetFlag(Package, L"-s") && ShellCommandLineGetFlag(Package, L"-l")) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CONFLICT), gShellDebug1HiiHandle, L"dmpstore", L"-l", L"-s"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if ((ShellCommandLineGetFlag(Package, L"-s") || ShellCommandLineGetFlag(Package, L"-l")) && ShellCommandLineGetFlag(Package, L"-d")) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CONFLICT), gShellDebug1HiiHandle, L"dmpstore", L"-l or -s", L"-d"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if ((ShellCommandLineGetFlag(Package, L"-s") || ShellCommandLineGetFlag(Package, L"-l")) && ShellCommandLineGetFlag(Package, L"-sfo")) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CONFLICT), gShellDebug1HiiHandle, L"dmpstore", L"-l or -s", L"-sfo"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // Determine the GUID to search for based on -all and -guid parameters + // + if (!ShellCommandLineGetFlag(Package, L"-all")) { + GuidStr = ShellCommandLineGetValue(Package, L"-guid"); + if (GuidStr != NULL) { + RStatus = StrToGuid (GuidStr, &GuidData); + if (RETURN_ERROR (RStatus) || (GuidStr[GUID_STRING_LENGTH] != L'\0')) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"dmpstore", GuidStr); + ShellStatus = SHELL_INVALID_PARAMETER; + } + Guid = &GuidData; + } else { + Guid = &gEfiGlobalVariableGuid; + } + } else { + Guid = NULL; + } + + // + // Get the Name of the variable to find + // + Name = ShellCommandLineGetRawValue(Package, 1); + + if (ShellStatus == SHELL_SUCCESS) { + if (ShellCommandLineGetFlag(Package, L"-s")) { + Type = DmpStoreSave; + File = ShellCommandLineGetValue(Package, L"-s"); + if (File == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDebug1HiiHandle, L"dmpstore", L"-s"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = ShellOpenFileByName (File, &FileHandle, EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ, 0); + if (!EFI_ERROR (Status)) { + // + // Delete existing file, but do not delete existing directory + // + FileInfo = ShellGetFileInfo (FileHandle); + if (FileInfo == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"dmpstore", File); + Status = EFI_DEVICE_ERROR; + } else { + if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_IS_DIRECTORY), gShellDebug1HiiHandle, L"dmpstore", File); + Status = EFI_INVALID_PARAMETER; + } else { + Status = ShellDeleteFile (&FileHandle); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_DELETE_FAIL), gShellDebug1HiiHandle, L"dmpstore", File); + } + } + FreePool (FileInfo); + } + } else if (Status == EFI_NOT_FOUND) { + // + // Good when file doesn't exist + // + Status = EFI_SUCCESS; + } else { + // + // Otherwise it's bad. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"dmpstore", File); + } + + if (!EFI_ERROR (Status)) { + Status = ShellOpenFileByName (File, &FileHandle, EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ, 0); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"dmpstore", File); + } + } + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_INVALID_PARAMETER; + } + } + } else if (ShellCommandLineGetFlag(Package, L"-l")) { + Type = DmpStoreLoad; + File = ShellCommandLineGetValue(Package, L"-l"); + if (File == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDebug1HiiHandle, L"dmpstore", L"-l"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = ShellOpenFileByName (File, &FileHandle, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"dmpstore", File); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + FileInfo = ShellGetFileInfo (FileHandle); + if (FileInfo == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"dmpstore", File); + ShellStatus = SHELL_DEVICE_ERROR; + } else { + if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_IS_DIRECTORY), gShellDebug1HiiHandle, L"dmpstore", File); + ShellStatus = SHELL_INVALID_PARAMETER; + } + FreePool (FileInfo); + } + } + } + } else if (ShellCommandLineGetFlag(Package, L"-d")) { + Type = DmpStoreDelete; + } + + if (ShellCommandLineGetFlag (Package,L"-sfo")) { + StandardFormatOutput = TRUE; + } + } + + if (ShellStatus == SHELL_SUCCESS) { + if (Type == DmpStoreSave) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_SAVE), gShellDebug1HiiHandle, File); + } else if (Type == DmpStoreLoad) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_LOAD), gShellDebug1HiiHandle, File); + } + ShellStatus = ProcessVariables (Name, Guid, Type, FileHandle, StandardFormatOutput); + if ((Type == DmpStoreLoad) || (Type == DmpStoreSave)) { + ShellCloseFile (&FileHandle); + } + } + } + } + + if (Package != NULL) { + ShellCommandLineFreeVarList (Package); + } + return ShellStatus; +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Edit.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Edit.c new file mode 100644 index 00000000..02a3097d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Edit.c @@ -0,0 +1,156 @@ +/** @file + Main file for Edit shell Debug1 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDebug1CommandsLib.h" +#include "TextEditor.h" + +/** + Function for 'edit' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunEdit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + CHAR16 *Buffer; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + LIST_ENTRY *Package; + CONST CHAR16 *Cwd; + CHAR16 *Nfs; + CHAR16 *Spot; + CONST CHAR16 *TempParam; +// SHELL_FILE_HANDLE TempHandle; + + Buffer = NULL; + ShellStatus = SHELL_SUCCESS; + Nfs = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"edit", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetCount(Package) > 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"edit"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Cwd = gEfiShellProtocol->GetCurDir(NULL); + if (Cwd == NULL) { + Cwd = ShellGetEnvironmentVariable(L"path"); + if (Cwd != NULL) { + Nfs = StrnCatGrow(&Nfs, NULL, Cwd+3, 0); + if (Nfs != NULL) { + Spot = StrStr(Nfs, L";"); + if (Spot != NULL) { + *Spot = CHAR_NULL; + } + Spot = StrStr(Nfs, L"\\"); + if (Spot != NULL) { + Spot[1] = CHAR_NULL; + } + gEfiShellProtocol->SetCurDir(NULL, Nfs); + FreePool(Nfs); + } + } + } + + Status = MainEditorInit (); + + if (EFI_ERROR (Status)) { + gST->ConOut->ClearScreen (gST->ConOut); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_MAIN_INIT_FAILED), gShellDebug1HiiHandle); + } else { + MainEditorBackup (); + + // + // if editor launched with file named + // + if (ShellCommandLineGetCount(Package) == 2) { + TempParam = ShellCommandLineGetRawValue(Package, 1); + ASSERT(TempParam != NULL); + FileBufferSetFileName (TempParam); +// if (EFI_ERROR(ShellFileExists(MainEditor.FileBuffer->FileName))) { +// Status = ShellOpenFileByName(MainEditor.FileBuffer->FileName, &TempHandle, EFI_FILE_MODE_CREATE|EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0); +// if (!EFI_ERROR(Status)) { +// ShellCloseFile(&TempHandle); +// } +// } + } + + Status = FileBufferRead (MainEditor.FileBuffer->FileName, FALSE); + if (!EFI_ERROR (Status)) { + MainEditorRefresh (); + + Status = MainEditorKeyInput (); + } + + if (Status != EFI_OUT_OF_RESOURCES) { + // + // back up the status string + // + Buffer = CatSPrint (NULL, L"%s", StatusBarGetString()); + } + + MainEditorCleanup (); + + // + // print editor exit code on screen + // + if (Status == EFI_SUCCESS) { + } else if (Status == EFI_OUT_OF_RESOURCES) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_GEN_OUT_MEM), gShellDebug1HiiHandle, L"edit"); + } else { + if (Buffer != NULL) { + if (StrCmp (Buffer, L"") != 0) { + // + // print out the status string + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_MAIN_BUFFER), gShellDebug1HiiHandle, Buffer); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_MAIN_UNKNOWN_EDITOR_ERR), gShellDebug1HiiHandle); + } + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_MAIN_UNKNOWN_EDITOR_ERR), gShellDebug1HiiHandle); + } + } + + if (Status != EFI_OUT_OF_RESOURCES) { + SHELL_FREE_NON_NULL (Buffer); + } + } + } + ShellCommandLineFreeVarList (Package); + } + return ShellStatus; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.c new file mode 100644 index 00000000..3c3f00fb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.c @@ -0,0 +1,3321 @@ +/** @file + Implements filebuffer interface functions. + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "TextEditor.h" +#include +#include + +EFI_EDITOR_FILE_BUFFER FileBuffer; +EFI_EDITOR_FILE_BUFFER FileBufferBackupVar; + +// +// for basic initialization of FileBuffer +// +EFI_EDITOR_FILE_BUFFER FileBufferConst = { + NULL, + FileTypeUnicode, + NULL, + NULL, + 0, + { + 0, + 0 + }, + { + 0, + 0 + }, + { + 0, + 0 + }, + { + 0, + 0 + }, + FALSE, + TRUE, + FALSE, + NULL +}; + +// +// the whole edit area needs to be refreshed +// +BOOLEAN FileBufferNeedRefresh; + +// +// only the current line in edit area needs to be refresh +// +BOOLEAN FileBufferOnlyLineNeedRefresh; + +BOOLEAN FileBufferMouseNeedRefresh; + +extern BOOLEAN EditorMouseAction; + +/** + Initialization function for FileBuffer. + + @param EFI_SUCCESS The initialization was successful. + @param EFI_LOAD_ERROR A default name could not be created. + @param EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +FileBufferInit ( + VOID + ) +{ + // + // basically initialize the FileBuffer + // + CopyMem (&FileBuffer , &FileBufferConst, sizeof (EFI_EDITOR_FILE_BUFFER)); + CopyMem (&FileBufferBackupVar, &FileBufferConst, sizeof (EFI_EDITOR_FILE_BUFFER)); + + // + // set default FileName + // + FileBuffer.FileName = EditGetDefaultFileName (L"txt"); + if (FileBuffer.FileName == NULL) { + return EFI_LOAD_ERROR; + } + + FileBuffer.ListHead = AllocateZeroPool (sizeof (LIST_ENTRY)); + if (FileBuffer.ListHead == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + InitializeListHead (FileBuffer.ListHead); + + FileBuffer.DisplayPosition.Row = 2; + FileBuffer.DisplayPosition.Column = 1; + FileBuffer.LowVisibleRange.Row = 2; + FileBuffer.LowVisibleRange.Column = 1; + + FileBufferNeedRefresh = FALSE; + FileBufferMouseNeedRefresh = FALSE; + FileBufferOnlyLineNeedRefresh = FALSE; + + return EFI_SUCCESS; +} + +/** + Backup function for FileBuffer. Only backup the following items: + Mouse/Cursor position + File Name, Type, ReadOnly, Modified + Insert Mode + + This is for making the file buffer refresh as few as possible. + + @retval EFI_SUCCESS The backup operation was successful. +**/ +EFI_STATUS +FileBufferBackup ( + VOID + ) +{ + FileBufferBackupVar.MousePosition = FileBuffer.MousePosition; + + SHELL_FREE_NON_NULL (FileBufferBackupVar.FileName); + FileBufferBackupVar.FileName = NULL; + FileBufferBackupVar.FileName = StrnCatGrow (&FileBufferBackupVar.FileName, NULL, FileBuffer.FileName, 0); + + FileBufferBackupVar.ModeInsert = FileBuffer.ModeInsert; + FileBufferBackupVar.FileType = FileBuffer.FileType; + + FileBufferBackupVar.FilePosition = FileBuffer.FilePosition; + FileBufferBackupVar.LowVisibleRange = FileBuffer.LowVisibleRange; + + FileBufferBackupVar.FileModified = FileBuffer.FileModified; + FileBufferBackupVar.ReadOnly = FileBuffer.ReadOnly; + + return EFI_SUCCESS; +} + +/** + Advance to the next Count lines + + @param[in] Count The line number to advance by. + @param[in] CurrentLine The pointer to the current line structure. + @param[in] LineList The pointer to the linked list of lines. + + @retval NULL There was an error. + @return The line structure after the advance. +**/ +EFI_EDITOR_LINE * +InternalEditorMiscLineAdvance ( + IN CONST UINTN Count, + IN CONST EFI_EDITOR_LINE *CurrentLine, + IN CONST LIST_ENTRY *LineList + ) + +{ + UINTN Index; + CONST EFI_EDITOR_LINE *Line; + + if (CurrentLine == NULL || LineList == NULL) { + return NULL; + } + + for (Line = CurrentLine, Index = 0; Index < Count; Index++) { + // + // if already last line + // + if (Line->Link.ForwardLink == LineList) { + return NULL; + } + + Line = CR (Line->Link.ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + } + + return ((EFI_EDITOR_LINE *)Line); +} + +/** + Retreat to the previous Count lines. + + @param[in] Count The line number to retreat by. + @param[in] CurrentLine The pointer to the current line structure. + @param[in] LineList The pointer to the linked list of lines. + + @retval NULL There was an error. + @return The line structure after the retreat. +**/ +EFI_EDITOR_LINE * +InternalEditorMiscLineRetreat ( + IN CONST UINTN Count, + IN CONST EFI_EDITOR_LINE *CurrentLine, + IN CONST LIST_ENTRY *LineList + ) + +{ + UINTN Index; + CONST EFI_EDITOR_LINE *Line; + + if (CurrentLine == NULL || LineList == NULL) { + return NULL; + } + + for (Line = CurrentLine, Index = 0; Index < Count; Index++) { + // + // already the first line + // + if (Line->Link.BackLink == LineList) { + return NULL; + } + + Line = CR (Line->Link.BackLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + } + + return ((EFI_EDITOR_LINE *)Line); +} + +/** + Advance/Retreat lines + + @param[in] Count line number to advance/retreat + >0 : advance + <0 : retreat + + @retval NULL An error occurred. + @return The line after advance/retreat. +**/ +EFI_EDITOR_LINE * +MoveLine ( + IN CONST INTN Count + ) +{ + EFI_EDITOR_LINE *Line; + UINTN AbsCount; + + // + // if < 0, then retreat + // if > 0, the advance + // + if (Count <= 0) { + AbsCount = (UINTN)ABS(Count); + Line = InternalEditorMiscLineRetreat (AbsCount,MainEditor.FileBuffer->CurrentLine,MainEditor.FileBuffer->ListHead); + } else { + Line = InternalEditorMiscLineAdvance ((UINTN)Count,MainEditor.FileBuffer->CurrentLine,MainEditor.FileBuffer->ListHead); + } + + return Line; +} + +/** + Function to update the 'screen' to display the mouse position. + + @retval EFI_SUCCESS The backup operation was successful. +**/ +EFI_STATUS +FileBufferRestoreMousePosition ( + VOID + ) +{ + EFI_EDITOR_COLOR_UNION Orig; + EFI_EDITOR_COLOR_UNION New; + UINTN FRow; + UINTN FColumn; + BOOLEAN HasCharacter; + EFI_EDITOR_LINE *CurrentLine; + EFI_EDITOR_LINE *Line; + CHAR16 Value; + + // + // variable initialization + // + Line = NULL; + + if (MainEditor.MouseSupported) { + + if (FileBufferMouseNeedRefresh) { + + FileBufferMouseNeedRefresh = FALSE; + + // + // if mouse position not moved and only mouse action + // so do not need to refresh mouse position + // + if ((FileBuffer.MousePosition.Row == FileBufferBackupVar.MousePosition.Row && + FileBuffer.MousePosition.Column == FileBufferBackupVar.MousePosition.Column) + && EditorMouseAction) { + return EFI_SUCCESS; + } + // + // backup the old screen attributes + // + Orig = MainEditor.ColorAttributes; + New.Data = 0; + New.Colors.Foreground = Orig.Colors.Background & 0xF; + New.Colors.Background = Orig.Colors.Foreground & 0x7; + + // + // clear the old mouse position + // + FRow = FileBuffer.LowVisibleRange.Row + FileBufferBackupVar.MousePosition.Row - 2; + + FColumn = FileBuffer.LowVisibleRange.Column + FileBufferBackupVar.MousePosition.Column - 1; + + HasCharacter = TRUE; + if (FRow > FileBuffer.NumLines) { + HasCharacter = FALSE; + } else { + CurrentLine = FileBuffer.CurrentLine; + Line = MoveLine (FRow - FileBuffer.FilePosition.Row); + + if (Line == NULL || FColumn > Line->Size) { + HasCharacter = FALSE; + } + + FileBuffer.CurrentLine = CurrentLine; + } + + ShellPrintEx ( + (INT32)FileBufferBackupVar.MousePosition.Column - 1, + (INT32)FileBufferBackupVar.MousePosition.Row - 1, + L" " + ); + + if (HasCharacter) { + Value = (Line->Buffer[FColumn - 1]); + ShellPrintEx ( + (INT32)FileBufferBackupVar.MousePosition.Column - 1, + (INT32)FileBufferBackupVar.MousePosition.Row - 1, + L"%c", + Value + ); + } + // + // set the new mouse position + // + gST->ConOut->SetAttribute (gST->ConOut, New.Data & 0x7F); + + // + // clear the old mouse position + // + FRow = FileBuffer.LowVisibleRange.Row + FileBuffer.MousePosition.Row - 2; + FColumn = FileBuffer.LowVisibleRange.Column + FileBuffer.MousePosition.Column - 1; + + HasCharacter = TRUE; + if (FRow > FileBuffer.NumLines) { + HasCharacter = FALSE; + } else { + CurrentLine = FileBuffer.CurrentLine; + Line = MoveLine (FRow - FileBuffer.FilePosition.Row); + + if (Line == NULL || FColumn > Line->Size) { + HasCharacter = FALSE; + } + + FileBuffer.CurrentLine = CurrentLine; + } + + ShellPrintEx ( + (INT32)FileBuffer.MousePosition.Column - 1, + (INT32)FileBuffer.MousePosition.Row - 1, + L" " + ); + + if (HasCharacter) { + Value = Line->Buffer[FColumn - 1]; + ShellPrintEx ( + (INT32)FileBuffer.MousePosition.Column - 1, + (INT32)FileBuffer.MousePosition.Row - 1, + L"%c", + Value + ); + } + // + // end of HasCharacter + // + gST->ConOut->SetAttribute (gST->ConOut, Orig.Data); + } + // + // end of MouseNeedRefresh + // + } + // + // end of MouseSupported + // + return EFI_SUCCESS; +} + +/** + Free all the lines in FileBuffer + Fields affected: + Lines + CurrentLine + NumLines + ListHead + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +FileBufferFreeLines ( + VOID + ) +{ + LIST_ENTRY *Link; + EFI_EDITOR_LINE *Line; + + // + // free all the lines + // + if (FileBuffer.Lines != NULL) { + + Line = FileBuffer.Lines; + Link = &(Line->Link); + do { + Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + Link = Link->ForwardLink; + + // + // free line's buffer and line itself + // + LineFree (Line); + } while (Link != FileBuffer.ListHead); + } + // + // clean the line list related structure + // + FileBuffer.Lines = NULL; + FileBuffer.CurrentLine = NULL; + FileBuffer.NumLines = 0; + + FileBuffer.ListHead->ForwardLink = FileBuffer.ListHead; + FileBuffer.ListHead->BackLink = FileBuffer.ListHead; + + return EFI_SUCCESS; +} + +/** + Cleanup function for FileBuffer. + + @retval EFI_SUCCESS The cleanup was successful. +**/ +EFI_STATUS +FileBufferCleanup ( + VOID + ) +{ + EFI_STATUS Status; + + SHELL_FREE_NON_NULL (FileBuffer.FileName); + + // + // free all the lines + // + Status = FileBufferFreeLines (); + + SHELL_FREE_NON_NULL (FileBuffer.ListHead); + FileBuffer.ListHead = NULL; + + SHELL_FREE_NON_NULL (FileBufferBackupVar.FileName); + return Status; + +} + +/** + Print a line specified by Line on a row specified by Row of the screen. + + @param[in] Line The line to print. + @param[in] Row The row on the screen to print onto (begin from 1). + + @retval EFI_SUCCESS The printing was successful. +**/ +EFI_STATUS +FileBufferPrintLine ( + IN CONST EFI_EDITOR_LINE *Line, + IN CONST UINTN Row + ) +{ + + CHAR16 *Buffer; + UINTN Limit; + CHAR16 *PrintLine; + CHAR16 *PrintLine2; + UINTN BufLen; + + // + // print start from correct character + // + Buffer = Line->Buffer + FileBuffer.LowVisibleRange.Column - 1; + + Limit = Line->Size - FileBuffer.LowVisibleRange.Column + 1; + if (Limit > Line->Size) { + Limit = 0; + } + + BufLen = (MainEditor.ScreenSize.Column + 1) * sizeof (CHAR16); + PrintLine = AllocatePool (BufLen); + if (PrintLine != NULL) { + StrnCpyS (PrintLine, BufLen/sizeof(CHAR16), Buffer, MIN(Limit, MainEditor.ScreenSize.Column)); + for (Limit = StrLen (PrintLine); Limit < MainEditor.ScreenSize.Column; Limit++) { + PrintLine[Limit] = L' '; + } + + PrintLine[MainEditor.ScreenSize.Column] = CHAR_NULL; + + PrintLine2 = AllocatePool (BufLen * 2); + if (PrintLine2 != NULL) { + ShellCopySearchAndReplace(PrintLine, PrintLine2, BufLen * 2, L"%", L"^%", FALSE, FALSE); + + ShellPrintEx ( + 0, + (INT32)Row - 1, + L"%s", + PrintLine2 + ); + FreePool (PrintLine2); + } + FreePool (PrintLine); + } + + return EFI_SUCCESS; +} + +/** + Set the cursor position according to FileBuffer.DisplayPosition. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +FileBufferRestorePosition ( + VOID + ) +{ + // + // set cursor position + // + return (gST->ConOut->SetCursorPosition ( + gST->ConOut, + FileBuffer.DisplayPosition.Column - 1, + FileBuffer.DisplayPosition.Row - 1 + )); +} + +/** + Refresh the screen with whats in the buffer. + + @retval EFI_SUCCESS The refresh was successful. + @retval EFI_LOAD_ERROR There was an error finding what to write. +**/ +EFI_STATUS +FileBufferRefresh ( + VOID + ) +{ + LIST_ENTRY *Link; + EFI_EDITOR_LINE *Line; + UINTN Row; + + // + // if it's the first time after editor launch, so should refresh + // + if (!EditorFirst) { + // + // no definite required refresh + // and file position displayed on screen has not been changed + // + if (!FileBufferNeedRefresh && + !FileBufferOnlyLineNeedRefresh && + FileBufferBackupVar.LowVisibleRange.Row == FileBuffer.LowVisibleRange.Row && + FileBufferBackupVar.LowVisibleRange.Column == FileBuffer.LowVisibleRange.Column + ) { + + FileBufferRestoreMousePosition (); + FileBufferRestorePosition (); + + return EFI_SUCCESS; + } + } + + gST->ConOut->EnableCursor (gST->ConOut, FALSE); + + // + // only need to refresh current line + // + if (FileBufferOnlyLineNeedRefresh && + FileBufferBackupVar.LowVisibleRange.Row == FileBuffer.LowVisibleRange.Row && + FileBufferBackupVar.LowVisibleRange.Column == FileBuffer.LowVisibleRange.Column + ) { + + EditorClearLine (FileBuffer.DisplayPosition.Row, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row); + FileBufferPrintLine ( + FileBuffer.CurrentLine, + FileBuffer.DisplayPosition.Row + ); + } else { + // + // the whole edit area need refresh + // + + // + // no line + // + if (FileBuffer.Lines == NULL) { + FileBufferRestoreMousePosition (); + FileBufferRestorePosition (); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + + return EFI_SUCCESS; + } + // + // get the first line that will be displayed + // + Line = MoveLine (FileBuffer.LowVisibleRange.Row - FileBuffer.FilePosition.Row); + if (Line == NULL) { + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + + return EFI_LOAD_ERROR; + } + + Link = &(Line->Link); + Row = 2; + do { + Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + + // + // print line at row + // + FileBufferPrintLine (Line, Row); + + Link = Link->ForwardLink; + Row++; + } while (Link != FileBuffer.ListHead && Row <= (MainEditor.ScreenSize.Row - 1)); + // + // while not file end and not screen full + // + while (Row <= (MainEditor.ScreenSize.Row - 1)) { + EditorClearLine (Row, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row); + Row++; + } + } + + FileBufferRestoreMousePosition (); + FileBufferRestorePosition (); + + FileBufferNeedRefresh = FALSE; + FileBufferOnlyLineNeedRefresh = FALSE; + + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + return EFI_SUCCESS; +} + +/** + Create a new line and append it to the line list. + Fields affected: + NumLines + Lines + + @retval NULL The create line failed. + @return The line created. +**/ +EFI_EDITOR_LINE * +FileBufferCreateLine ( + VOID + ) +{ + EFI_EDITOR_LINE *Line; + + // + // allocate a line structure + // + Line = AllocateZeroPool (sizeof (EFI_EDITOR_LINE)); + if (Line == NULL) { + return NULL; + } + // + // initialize the structure + // + Line->Signature = LINE_LIST_SIGNATURE; + Line->Size = 0; + Line->TotalSize = 0; + Line->Type = NewLineTypeDefault; + + // + // initial buffer of the line is "\0" + // + ASSERT(CHAR_NULL == CHAR_NULL); + Line->Buffer = CatSPrint (NULL, L"\0"); + if (Line->Buffer == NULL) { + return NULL; + } + + FileBuffer.NumLines++; + + // + // insert the line into line list + // + InsertTailList (FileBuffer.ListHead, &Line->Link); + + if (FileBuffer.Lines == NULL) { + FileBuffer.Lines = CR (FileBuffer.ListHead->ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + } + + return Line; +} + +/** + Set FileName field in FileBuffer. + + @param Str The file name to set. + + @retval EFI_SUCCESS The filename was successfully set. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_INVALID_PARAMETER Str is not a valid filename. +**/ +EFI_STATUS +FileBufferSetFileName ( + IN CONST CHAR16 *Str + ) +{ + // + // Verify the parameters + // + if (!IsValidFileName(Str)) { + return (EFI_INVALID_PARAMETER); + } + // + // free the old file name + // + SHELL_FREE_NON_NULL (FileBuffer.FileName); + + // + // Allocate and set the new name + // + FileBuffer.FileName = CatSPrint (NULL, L"%s", Str); + if (FileBuffer.FileName == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} +/** + Free the existing file lines and reset the modified flag. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +FileBufferFree ( + VOID + ) +{ + // + // free all the lines + // + FileBufferFreeLines (); + FileBuffer.FileModified = FALSE; + + return EFI_SUCCESS; +} + + +/** + Read a file from disk into the FileBuffer. + + @param[in] FileName The filename to read. + @param[in] Recover TRUE if is for recover mode, no information printouts. + + @retval EFI_SUCCESS The load was successful. + @retval EFI_LOAD_ERROR The load failed. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_INVALID_PARAMETER FileName is a directory. +**/ +EFI_STATUS +FileBufferRead ( + IN CONST CHAR16 *FileName, + IN CONST BOOLEAN Recover + ) +{ + EFI_EDITOR_LINE *Line; + EE_NEWLINE_TYPE Type; + UINTN LoopVar1; + UINTN LoopVar2; + UINTN LineSize; + VOID *Buffer; + CHAR16 *UnicodeBuffer; + UINT8 *AsciiBuffer; + UINTN FileSize; + SHELL_FILE_HANDLE FileHandle; + BOOLEAN CreateFile; + EFI_STATUS Status; + UINTN LineSizeBackup; + EFI_FILE_INFO *Info; + + Line = NULL; + LoopVar1 = 0; + FileSize = 0; + UnicodeBuffer = NULL; + Type = NewLineTypeDefault; + FileHandle = NULL; + CreateFile = FALSE; + + // + // in this function, when you return error ( except EFI_OUT_OF_RESOURCES ) + // you should set status string via StatusBarSetStatusString(L"blah") + // since this function maybe called before the editorhandleinput loop + // so any error will cause editor return + // so if you want to print the error status + // you should set the status string + // + + // + // try to open the file + // + Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ, 0); + + if (!EFI_ERROR(Status)) { + CreateFile = FALSE; + if (FileHandle == NULL) { + StatusBarSetStatusString (L"Disk Error"); + return EFI_LOAD_ERROR; + } + + Info = ShellGetFileInfo(FileHandle); + + if (Info->Attribute & EFI_FILE_DIRECTORY) { + StatusBarSetStatusString (L"Directory Can Not Be Edited"); + FreePool (Info); + return EFI_INVALID_PARAMETER; + } + + if (Info->Attribute & EFI_FILE_READ_ONLY) { + FileBuffer.ReadOnly = TRUE; + } else { + FileBuffer.ReadOnly = FALSE; + } + // + // get file size + // + FileSize = (UINTN) Info->FileSize; + + FreePool (Info); + } else if (Status == EFI_NOT_FOUND) { + // + // file not exists. add create and try again + // + Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0); + if (EFI_ERROR (Status)) { + if (Status == EFI_WRITE_PROTECTED || + Status == EFI_ACCESS_DENIED || + Status == EFI_NO_MEDIA || + Status == EFI_MEDIA_CHANGED + ) { + StatusBarSetStatusString (L"Access Denied"); + } else if (Status == EFI_DEVICE_ERROR || Status == EFI_VOLUME_CORRUPTED || Status == EFI_VOLUME_FULL) { + StatusBarSetStatusString (L"Disk Error"); + } else { + StatusBarSetStatusString (L"Invalid File Name or Current-working-directory"); + } + + return Status; + } else { + // + // it worked. now delete it and move on with the name (now validated) + // + Status = ShellDeleteFile (&FileHandle); + if (Status == EFI_WARN_DELETE_FAILURE) { + Status = EFI_ACCESS_DENIED; + } + FileHandle = NULL; + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"Access Denied"); + return Status; + } + } + // + // file doesn't exist, so set CreateFile to TRUE + // + CreateFile = TRUE; + FileBuffer.ReadOnly = FALSE; + + // + // all the check ends + // so now begin to set file name, free lines + // + if (StrCmp (FileName, FileBuffer.FileName) != 0) { + FileBufferSetFileName (FileName); + } + // + // free the old lines + // + FileBufferFree (); + + } + // + // the file exists + // + if (!CreateFile) { + // + // allocate buffer to read file + // + Buffer = AllocateZeroPool (FileSize); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // read file into Buffer + // + Status = ShellReadFile (FileHandle, &FileSize, Buffer); + ShellCloseFile(&FileHandle); + FileHandle = NULL; + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"Read File Failed"); + SHELL_FREE_NON_NULL (Buffer); + return EFI_LOAD_ERROR; + } + // + // nothing in this file + // + if (FileSize == 0) { + SHELL_FREE_NON_NULL (Buffer); + // + // since has no head, so only can be an ASCII file + // + FileBuffer.FileType = FileTypeAscii; + + goto Done; + } + + AsciiBuffer = Buffer; + + if (FileSize < 2) { + // + // size < Unicode file header, so only can be ASCII file + // + FileBuffer.FileType = FileTypeAscii; + } else { + // + // Unicode file + // + if (*(UINT16 *) Buffer == EFI_UNICODE_BYTE_ORDER_MARK) { + // + // Unicode file's size should be even + // + if ((FileSize % 2) != 0) { + StatusBarSetStatusString (L"File Format Wrong"); + SHELL_FREE_NON_NULL (Buffer); + return EFI_LOAD_ERROR; + } + + FileSize /= 2; + + FileBuffer.FileType = FileTypeUnicode; + UnicodeBuffer = Buffer; + + // + // pass this 0xff and 0xfe + // + UnicodeBuffer++; + FileSize--; + } else { + FileBuffer.FileType = FileTypeAscii; + } + // + // end of AsciiBuffer == + // + } + // + // end of FileSize < 2 + // all the check ends + // so now begin to set file name, free lines + // + if (StrCmp (FileName, FileBuffer.FileName) != 0) { + FileBufferSetFileName (FileName); + } + + // + // free the old lines + // + FileBufferFree (); + + // + // parse file content line by line + // + for (LoopVar1 = 0; LoopVar1 < FileSize; LoopVar1++) { + Type = NewLineTypeUnknown; + + for (LineSize = LoopVar1; LineSize < FileSize; LineSize++) { + if (FileBuffer.FileType == FileTypeAscii) { + if (AsciiBuffer[LineSize] == CHAR_CARRIAGE_RETURN) { + Type = NewLineTypeCarriageReturn; + + // + // has LF following + // + if (LineSize < FileSize - 1) { + if (AsciiBuffer[LineSize + 1] == CHAR_LINEFEED) { + Type = NewLineTypeCarriageReturnLineFeed; + } + } + + break; + } else if (AsciiBuffer[LineSize] == CHAR_LINEFEED) { + Type = NewLineTypeLineFeed; + + // + // has CR following + // + if (LineSize < FileSize - 1) { + if (AsciiBuffer[LineSize + 1] == CHAR_CARRIAGE_RETURN) { + Type = NewLineTypeLineFeedCarriageReturn; + } + } + + break; + } + } else { + if (UnicodeBuffer[LineSize] == CHAR_CARRIAGE_RETURN) { + Type = NewLineTypeCarriageReturn; + + // + // has LF following + // + if (LineSize < FileSize - 1) { + if (UnicodeBuffer[LineSize + 1] == CHAR_LINEFEED) { + Type = NewLineTypeCarriageReturnLineFeed; + } + } + + break; + } else if (UnicodeBuffer[LineSize] == CHAR_LINEFEED) { + Type = NewLineTypeLineFeed; + + // + // has CR following + // + if (LineSize < FileSize - 1) { + if (UnicodeBuffer[LineSize + 1] == CHAR_CARRIAGE_RETURN) { + Type = NewLineTypeLineFeedCarriageReturn; + } + } + + break; + } + } + // + // endif == ASCII + // + } + // + // end of for LineSize + // + // if the type is wrong, then exit + // + if (Type == NewLineTypeUnknown) { + // + // Now if Type is NewLineTypeUnknown, it should be file end + // + Type = NewLineTypeDefault; + } + + LineSizeBackup = LineSize; + + // + // create a new line + // + Line = FileBufferCreateLine (); + if (Line == NULL) { + SHELL_FREE_NON_NULL (Buffer); + return EFI_OUT_OF_RESOURCES; + } + // + // calculate file length + // + LineSize -= LoopVar1; + + // + // Unicode and one CHAR_NULL + // + SHELL_FREE_NON_NULL (Line->Buffer); + Line->Buffer = AllocateZeroPool (LineSize * 2 + 2); + + if (Line->Buffer == NULL) { + RemoveEntryList (&Line->Link); + return EFI_OUT_OF_RESOURCES; + } + // + // copy this line to Line->Buffer + // + for (LoopVar2 = 0; LoopVar2 < LineSize; LoopVar2++) { + if (FileBuffer.FileType == FileTypeAscii) { + Line->Buffer[LoopVar2] = (CHAR16) AsciiBuffer[LoopVar1]; + } else { + Line->Buffer[LoopVar2] = UnicodeBuffer[LoopVar1]; + } + + LoopVar1++; + } + // + // LoopVar1 now points to where CHAR_CARRIAGE_RETURN or CHAR_LINEFEED; + // + Line->Buffer[LineSize] = 0; + + Line->Size = LineSize; + Line->TotalSize = LineSize; + Line->Type = Type; + + if (Type == NewLineTypeCarriageReturnLineFeed || Type == NewLineTypeLineFeedCarriageReturn) { + LoopVar1++; + } + + // + // last character is a return, SO create a new line + // + if (((Type == NewLineTypeCarriageReturnLineFeed || Type == NewLineTypeLineFeedCarriageReturn) && LineSizeBackup == FileSize - 2) || + ((Type == NewLineTypeLineFeed || Type == NewLineTypeCarriageReturn) && LineSizeBackup == FileSize - 1) + ) { + Line = FileBufferCreateLine (); + if (Line == NULL) { + SHELL_FREE_NON_NULL (Buffer); + return EFI_OUT_OF_RESOURCES; + } + } + // + // end of if + // + } + // + // end of LoopVar1 + // + SHELL_FREE_NON_NULL (Buffer); + + } + // + // end of if CreateFile + // +Done: + + FileBuffer.DisplayPosition.Row = 2; + FileBuffer.DisplayPosition.Column = 1; + FileBuffer.LowVisibleRange.Row = 1; + FileBuffer.LowVisibleRange.Column = 1; + FileBuffer.FilePosition.Row = 1; + FileBuffer.FilePosition.Column = 1; + FileBuffer.MousePosition.Row = 2; + FileBuffer.MousePosition.Column = 1; + + if (!Recover) { + UnicodeBuffer = CatSPrint (NULL, L"%d Lines Read", FileBuffer.NumLines); + if (UnicodeBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + StatusBarSetStatusString (UnicodeBuffer); + FreePool (UnicodeBuffer); + } +/* + // + // check whether we have fs?: in filename + // + LoopVar1 = 0; + FSMappingPtr = NULL; + while (FileName[LoopVar1] != 0) { + if (FileName[LoopVar1] == L':') { + FSMappingPtr = &FileName[LoopVar1]; + break; + } + + LoopVar1++; + } + + if (FSMappingPtr == NULL) { + CurDir = ShellGetCurrentDir (NULL); + } else { + LoopVar1 = 0; + LoopVar2 = 0; + while (FileName[LoopVar1] != 0) { + if (FileName[LoopVar1] == L':') { + break; + } + + FSMapping[LoopVar2++] = FileName[LoopVar1]; + + LoopVar1++; + } + + FSMapping[LoopVar2] = 0; + CurDir = ShellGetCurrentDir (FSMapping); + } + + if (CurDir != NULL) { + for (LoopVar1 = 0; LoopVar1 < StrLen (CurDir) && CurDir[LoopVar1] != ':'; LoopVar1++); + + CurDir[LoopVar1] = 0; + DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) ShellGetMap (CurDir); + FreePool (CurDir); + } else { + return EFI_LOAD_ERROR; + } + + Status = LibDevicePathToInterface ( + &gEfiSimpleFileSystemProtocolGuid, + DevicePath, + (VOID **) &Vol + ); + if (EFI_ERROR (Status)) { + return EFI_LOAD_ERROR; + } + + Status = Vol->OpenVolume (Vol, &RootFs); + if (EFI_ERROR (Status)) { + return EFI_LOAD_ERROR; + } + // + // Get volume information of file system + // + Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + 100; + VolumeInfo = (EFI_FILE_SYSTEM_INFO *) AllocateZeroPool (Size); + Status = RootFs->GetInfo (RootFs, &gEfiFileSystemInfoGuid, &Size, VolumeInfo); + if (EFI_ERROR (Status)) { + RootFs->Close (RootFs); + return EFI_LOAD_ERROR; + } + + if (VolumeInfo->ReadOnly) { + StatusBarSetStatusString (L"WARNING: Volume Read Only"); + } + + FreePool (VolumeInfo); + RootFs->Close (RootFs); + } +// +*/ + // + // has line + // + if (FileBuffer.Lines != 0) { + FileBuffer.CurrentLine = CR (FileBuffer.ListHead->ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + } else { + // + // create a dummy line + // + Line = FileBufferCreateLine (); + if (Line == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + FileBuffer.CurrentLine = Line; + } + + FileBuffer.FileModified = FALSE; + FileBufferNeedRefresh = TRUE; + FileBufferOnlyLineNeedRefresh = FALSE; + FileBufferMouseNeedRefresh = TRUE; + + + return EFI_SUCCESS; +} + +/** + According to FileBuffer.NewLineType & FileBuffer.FileType, + get the return buffer and size. + + @param[in] Type The type of line. + @param[out] Buffer The buffer to fill. + @param[out] Size The amount of the buffer used on return. +**/ +VOID +GetNewLine ( + IN CONST EE_NEWLINE_TYPE Type, + OUT CHAR8 *Buffer, + OUT UINT8 *Size + ) +{ + UINT8 NewLineSize; + + // + // give new line buffer, + // and will judge unicode or ascii + // + NewLineSize = 0; + + // + // not legal new line type + // + if (Type != NewLineTypeLineFeed && Type != NewLineTypeCarriageReturn && Type != NewLineTypeCarriageReturnLineFeed && Type != NewLineTypeLineFeedCarriageReturn) { + *Size = 0; + return ; + } + // + // use_cr: give 0x0d + // + if (Type == NewLineTypeCarriageReturn) { + if (MainEditor.FileBuffer->FileType == FileTypeUnicode) { + Buffer[0] = 0x0d; + Buffer[1] = 0; + NewLineSize = 2; + } else { + Buffer[0] = 0x0d; + NewLineSize = 1; + } + + *Size = NewLineSize; + return ; + } + // + // use_lf: give 0x0a + // + if (Type == NewLineTypeLineFeed) { + if (MainEditor.FileBuffer->FileType == FileTypeUnicode) { + Buffer[0] = 0x0a; + Buffer[1] = 0; + NewLineSize = 2; + } else { + Buffer[0] = 0x0a; + NewLineSize = 1; + } + + *Size = NewLineSize; + return ; + } + // + // use_crlf: give 0x0d 0x0a + // + if (Type == NewLineTypeCarriageReturnLineFeed) { + if (MainEditor.FileBuffer->FileType == FileTypeUnicode) { + Buffer[0] = 0x0d; + Buffer[1] = 0; + Buffer[2] = 0x0a; + Buffer[3] = 0; + + NewLineSize = 4; + } else { + Buffer[0] = 0x0d; + Buffer[1] = 0x0a; + NewLineSize = 2; + } + + *Size = NewLineSize; + return ; + } + // + // use_lfcr: give 0x0a 0x0d + // + if (Type == NewLineTypeLineFeedCarriageReturn) { + if (MainEditor.FileBuffer->FileType == FileTypeUnicode) { + Buffer[0] = 0x0a; + Buffer[1] = 0; + Buffer[2] = 0x0d; + Buffer[3] = 0; + + NewLineSize = 4; + } else { + Buffer[0] = 0x0a; + Buffer[1] = 0x0d; + NewLineSize = 2; + } + + *Size = NewLineSize; + return ; + } + +} + +/** + Change a Unicode string to an ASCII string. + + @param[in] UStr The Unicode string. + @param[in] Length The maximum size of AStr. + @param[out] AStr ASCII string to pass out. + + @return The actuall length. +**/ +UINTN +UnicodeToAscii ( + IN CONST CHAR16 *UStr, + IN CONST UINTN Length, + OUT CHAR8 *AStr + ) +{ + UINTN Index; + + // + // just buffer copy, not character copy + // + for (Index = 0; Index < Length; Index++) { + *AStr++ = (CHAR8) *UStr++; + } + + return Index; +} + +/** + Save lines in FileBuffer to disk + + @param[in] FileName The file name for writing. + + @retval EFI_SUCCESS Data was written. + @retval EFI_LOAD_ERROR + @retval EFI_OUT_OF_RESOURCES There were not enough resources to write the file. +**/ +EFI_STATUS +FileBufferSave ( + IN CONST CHAR16 *FileName + ) +{ + SHELL_FILE_HANDLE FileHandle; + LIST_ENTRY *Link; + EFI_EDITOR_LINE *Line; + CHAR16 *Str; + + EFI_STATUS Status; + UINTN Length; + UINTN NumLines; + CHAR8 NewLineBuffer[4]; + UINT8 NewLineSize; + + EFI_FILE_INFO *Info; + + UINT64 Attribute; + + EE_NEWLINE_TYPE Type; + + UINTN TotalSize; + // + // 2M + // + CHAR8 *Cache; + UINTN LeftSize; + UINTN Size; + CHAR8 *Ptr; + + Length = 0; + // + // 2M + // + TotalSize = 0x200000; + + Attribute = 0; + + + + // + // if is the old file + // + if (FileBuffer.FileName != NULL && StrCmp (FileName, FileBuffer.FileName) == 0) { + // + // file has not been modified + // + if (!FileBuffer.FileModified) { + return EFI_SUCCESS; + } + + // + // if file is read-only, set error + // + if (FileBuffer.ReadOnly) { + StatusBarSetStatusString (L"Read Only File Can Not Be Saved"); + return EFI_SUCCESS; + } + } + + Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0); + + if (!EFI_ERROR (Status)) { + Info = ShellGetFileInfo(FileHandle); + + if (Info != NULL && Info->Attribute & EFI_FILE_DIRECTORY) { + StatusBarSetStatusString (L"Directory Can Not Be Saved"); + ShellCloseFile (&FileHandle); + FreePool(Info); + return EFI_LOAD_ERROR; + } + + if (Info != NULL) { + Attribute = Info->Attribute & ~EFI_FILE_READ_ONLY; + FreePool(Info); + } + + // + // if file exits, so delete it + // + Status = ShellDeleteFile (&FileHandle); + if (EFI_ERROR (Status) || Status == EFI_WARN_DELETE_FAILURE) { + StatusBarSetStatusString (L"Write File Failed"); + return EFI_LOAD_ERROR; + } + } + + Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, Attribute); + + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"Create File Failed"); + return EFI_LOAD_ERROR; + } + + // + // if file is Unicode file, write Unicode header to it. + // + if (FileBuffer.FileType == FileTypeUnicode) { + Length = 2; + Status = ShellWriteFile (FileHandle, &Length, (VOID*)&gUnicodeFileTag); + if (EFI_ERROR (Status)) { + ShellDeleteFile (&FileHandle); + return EFI_LOAD_ERROR; + } + } + + Cache = AllocateZeroPool (TotalSize); + if (Cache == NULL) { + ShellDeleteFile (&FileHandle); + return EFI_OUT_OF_RESOURCES; + } + + // + // write all the lines back to disk + // + NumLines = 0; + Type = NewLineTypeCarriageReturnLineFeed; + + Ptr = Cache; + LeftSize = TotalSize; + + for (Link = FileBuffer.ListHead->ForwardLink; Link != FileBuffer.ListHead; Link = Link->ForwardLink) { + Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + + if (Line->Type != NewLineTypeDefault) { + Type = Line->Type; + } + // + // newline character is at most 4 bytes ( two Unicode characters ) + // + Length = 4; + if (Line->Buffer != NULL && Line->Size != 0) { + if (FileBuffer.FileType == FileTypeAscii) { + Length += Line->Size; + } else { + Length += (Line->Size * 2); + } + // + // end if FileTypeAscii + // + } + + // + // no cache room left, so write cache to disk + // + if (LeftSize < Length) { + Size = TotalSize - LeftSize; + Status = ShellWriteFile (FileHandle, &Size, Cache); + if (EFI_ERROR (Status)) { + ShellDeleteFile (&FileHandle); + FreePool (Cache); + return EFI_LOAD_ERROR; + } + Ptr = Cache; + LeftSize = TotalSize; + } + + if (Line->Buffer != NULL && Line->Size != 0) { + if (FileBuffer.FileType == FileTypeAscii) { + UnicodeToAscii (Line->Buffer, Line->Size, Ptr); + Length = Line->Size; + } else { + Length = (Line->Size * 2); + CopyMem (Ptr, (CHAR8 *) Line->Buffer, Length); + } + // + // end if FileTypeAscii + // + Ptr += Length; + LeftSize -= Length; + + } + // + // end of if Line -> Buffer != NULL && Line -> Size != 0 + // + // if not the last line , write return buffer to disk + // + if (Link->ForwardLink != FileBuffer.ListHead) { + GetNewLine (Type, NewLineBuffer, &NewLineSize); + CopyMem (Ptr, (CHAR8 *) NewLineBuffer, NewLineSize); + + Ptr += NewLineSize; + LeftSize -= NewLineSize; + } + + NumLines++; + } + + if (TotalSize != LeftSize) { + Size = TotalSize - LeftSize; + Status = ShellWriteFile (FileHandle, &Size, Cache); + if (EFI_ERROR (Status)) { + ShellDeleteFile (&FileHandle); + FreePool (Cache); + return EFI_LOAD_ERROR; + } + } + + FreePool (Cache); + + ShellCloseFile(&FileHandle); + + FileBuffer.FileModified = FALSE; + + // + // set status string + // + Str = CatSPrint (NULL, L"%d Lines Written", NumLines); + if (Str == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + StatusBarSetStatusString (Str); + SHELL_FREE_NON_NULL (Str); + + // + // now everything is ready , you can set the new file name to filebuffer + // + if (FileName != NULL && FileBuffer.FileName != NULL && StrCmp (FileName, FileBuffer.FileName) != 0) { + // + // not the same + // + FileBufferSetFileName (FileName); + if (FileBuffer.FileName == NULL) { + ShellDeleteFile (&FileHandle); + return EFI_OUT_OF_RESOURCES; + } + } + + FileBuffer.ReadOnly = FALSE; + return EFI_SUCCESS; +} + +/** + Scroll cursor to left 1 character position. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +FileBufferScrollLeft ( + VOID + ) +{ + EFI_EDITOR_LINE *Line; + UINTN FRow; + UINTN FCol; + + Line = FileBuffer.CurrentLine; + + FRow = FileBuffer.FilePosition.Row; + FCol = FileBuffer.FilePosition.Column; + + // + // if already at start of this line, so move to the end of previous line + // + if (FCol <= 1) { + // + // has previous line + // + if (Line->Link.BackLink != FileBuffer.ListHead) { + FRow--; + Line = CR (Line->Link.BackLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + FCol = Line->Size + 1; + } else { + return EFI_SUCCESS; + } + } else { + // + // if not at start of this line, just move to previous column + // + FCol--; + } + + FileBufferMovePosition (FRow, FCol); + + return EFI_SUCCESS; +} + +/** + Delete a char in line + + @param[in, out] Line The line to delete in. + @param[in] Pos Position to delete the char at ( start from 0 ). +**/ +VOID +LineDeleteAt ( + IN OUT EFI_EDITOR_LINE *Line, + IN UINTN Pos + ) +{ + UINTN Index; + + // + // move the latter characters front + // + for (Index = Pos - 1; Index < Line->Size; Index++) { + Line->Buffer[Index] = Line->Buffer[Index + 1]; + } + + Line->Size--; +} + +/** + Concatenate Src into Dest. + + @param[in, out] Dest Destination string + @param[in] Src Src String. +**/ +VOID +LineCat ( + IN OUT EFI_EDITOR_LINE *Dest, + IN EFI_EDITOR_LINE *Src + ) +{ + CHAR16 *Str; + UINTN Size; + + Size = Dest->Size; + + Dest->Buffer[Size] = 0; + + // + // concatenate the two strings + // + Str = CatSPrint (NULL, L"%s%s", Dest->Buffer, Src->Buffer); + if (Str == NULL) { + Dest->Buffer = NULL; + return ; + } + + Dest->Size = Size + Src->Size; + Dest->TotalSize = Dest->Size; + + FreePool (Dest->Buffer); + FreePool (Src->Buffer); + + // + // put str to dest->buffer + // + Dest->Buffer = Str; +} + +/** + Delete the previous character. + + @retval EFI_SUCCESS The delete was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +FileBufferDoBackspace ( + VOID + ) +{ + EFI_EDITOR_LINE *Line; + EFI_EDITOR_LINE *End; + LIST_ENTRY *Link; + UINTN FileColumn; + + FileColumn = FileBuffer.FilePosition.Column; + + Line = FileBuffer.CurrentLine; + + // + // the first column + // + if (FileColumn == 1) { + // + // the first row + // + if (FileBuffer.FilePosition.Row == 1) { + return EFI_SUCCESS; + } + + FileBufferScrollLeft (); + + Line = FileBuffer.CurrentLine; + Link = Line->Link.ForwardLink; + End = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + + // + // concatenate this line with previous line + // + LineCat (Line, End); + if (Line->Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // remove End from line list + // + RemoveEntryList (&End->Link); + FreePool (End); + + FileBuffer.NumLines--; + + FileBufferNeedRefresh = TRUE; + FileBufferOnlyLineNeedRefresh = FALSE; + + } else { + // + // just delete the previous character + // + LineDeleteAt (Line, FileColumn - 1); + FileBufferScrollLeft (); + FileBufferOnlyLineNeedRefresh = TRUE; + } + + if (!FileBuffer.FileModified) { + FileBuffer.FileModified = TRUE; + } + + return EFI_SUCCESS; +} + +/** + Add a return into line at current position. + + @retval EFI_SUCCESS The insetrion of the character was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +FileBufferDoReturn ( + VOID + ) +{ + EFI_EDITOR_LINE *Line; + EFI_EDITOR_LINE *NewLine; + UINTN FileColumn; + UINTN Index; + CHAR16 *Buffer; + UINTN Row; + UINTN Col; + + FileBufferNeedRefresh = TRUE; + FileBufferOnlyLineNeedRefresh = FALSE; + + Line = FileBuffer.CurrentLine; + + FileColumn = FileBuffer.FilePosition.Column; + + NewLine = AllocateZeroPool (sizeof (EFI_EDITOR_LINE)); + if (NewLine == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + NewLine->Signature = LINE_LIST_SIGNATURE; + NewLine->Size = Line->Size - FileColumn + 1; + NewLine->TotalSize = NewLine->Size; + NewLine->Buffer = CatSPrint (NULL, L"\0"); + if (NewLine->Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + NewLine->Type = NewLineTypeDefault; + + if (NewLine->Size > 0) { + // + // UNICODE + CHAR_NULL + // + Buffer = AllocateZeroPool (2 * (NewLine->Size + 1)); + if (Buffer == NULL) { + FreePool (NewLine->Buffer); + FreePool (NewLine); + return EFI_OUT_OF_RESOURCES; + } + + FreePool (NewLine->Buffer); + + NewLine->Buffer = Buffer; + + for (Index = 0; Index < NewLine->Size; Index++) { + NewLine->Buffer[Index] = Line->Buffer[Index + FileColumn - 1]; + } + + NewLine->Buffer[NewLine->Size] = CHAR_NULL; + + Line->Buffer[FileColumn - 1] = CHAR_NULL; + Line->Size = FileColumn - 1; + } + // + // increase NumLines + // + FileBuffer.NumLines++; + + // + // insert it into the correct position of line list + // + NewLine->Link.BackLink = &(Line->Link); + NewLine->Link.ForwardLink = Line->Link.ForwardLink; + Line->Link.ForwardLink->BackLink = &(NewLine->Link); + Line->Link.ForwardLink = &(NewLine->Link); + + // + // move cursor to the start of next line + // + Row = FileBuffer.FilePosition.Row + 1; + Col = 1; + + FileBufferMovePosition (Row, Col); + + // + // set file is modified + // + if (!FileBuffer.FileModified) { + FileBuffer.FileModified = TRUE; + } + + return EFI_SUCCESS; +} + +/** + Delete current character from current line. This is the effect caused + by the 'del' key. + + @retval EFI_SUCCESS +**/ +EFI_STATUS +FileBufferDoDelete ( + VOID + ) +{ + EFI_EDITOR_LINE *Line; + EFI_EDITOR_LINE *Next; + LIST_ENTRY *Link; + UINTN FileColumn; + + Line = FileBuffer.CurrentLine; + FileColumn = FileBuffer.FilePosition.Column; + + // + // the last column + // + if (FileColumn >= Line->Size + 1) { + // + // the last line + // + if (Line->Link.ForwardLink == FileBuffer.ListHead) { + return EFI_SUCCESS; + } + // + // since last character, + // so will add the next line to this line + // + Link = Line->Link.ForwardLink; + Next = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + LineCat (Line, Next); + if (Line->Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + RemoveEntryList (&Next->Link); + FreePool (Next); + + FileBuffer.NumLines--; + + FileBufferNeedRefresh = TRUE; + FileBufferOnlyLineNeedRefresh = FALSE; + + } else { + // + // just delete current character + // + LineDeleteAt (Line, FileColumn); + FileBufferOnlyLineNeedRefresh = TRUE; + } + + if (!FileBuffer.FileModified) { + FileBuffer.FileModified = TRUE; + } + + return EFI_SUCCESS; +} + +/** + Scroll cursor to right 1 character. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +FileBufferScrollRight ( + VOID + ) +{ + EFI_EDITOR_LINE *Line; + UINTN FRow; + UINTN FCol; + + Line = FileBuffer.CurrentLine; + if (Line->Buffer == NULL) { + return EFI_SUCCESS; + } + + FRow = FileBuffer.FilePosition.Row; + FCol = FileBuffer.FilePosition.Column; + + // + // if already at end of this line, scroll it to the start of next line + // + if (FCol > Line->Size) { + // + // has next line + // + if (Line->Link.ForwardLink != FileBuffer.ListHead) { + FRow++; + FCol = 1; + } else { + return EFI_SUCCESS; + } + } else { + // + // if not at end of this line, just move to next column + // + FCol++; + } + + FileBufferMovePosition (FRow, FCol); + + return EFI_SUCCESS; +} + +/** + Insert a char into line + + + @param[in] Line The line to insert into. + @param[in] Char The char to insert. + @param[in] Pos The position to insert the char at ( start from 0 ). + @param[in] StrSize The current string size ( include CHAR_NULL ),unit is Unicode character. + + @return The new string size ( include CHAR_NULL ) ( unit is Unicode character ). +**/ +UINTN +LineStrInsert ( + IN EFI_EDITOR_LINE *Line, + IN CHAR16 Char, + IN UINTN Pos, + IN UINTN StrSize + ) +{ + UINTN Index; + CHAR16 *TempStringPtr; + CHAR16 *Str; + + Index = (StrSize) * 2; + + Str = Line->Buffer; + + // + // do not have free space + // + if (Line->TotalSize <= Line->Size) { + Str = ReallocatePool (Index, Index + 16, Str); + if (Str == NULL) { + return 0; + } + + Line->TotalSize += 8; + } + // + // move the later part of the string one character right + // + TempStringPtr = Str; + for (Index = StrSize; Index > Pos; Index--) { + TempStringPtr[Index] = TempStringPtr[Index - 1]; + } + // + // insert char into it. + // + TempStringPtr[Index] = Char; + + Line->Buffer = Str; + Line->Size++; + + return StrSize + 1; +} + +/** + Add a character to the current line. + + @param[in] Char The Character to input. + + @retval EFI_SUCCESS The input was succesful. +**/ +EFI_STATUS +FileBufferAddChar ( + IN CHAR16 Char + ) +{ + EFI_EDITOR_LINE *Line; + UINTN FilePos; + + Line = FileBuffer.CurrentLine; + + // + // only needs to refresh current line + // + FileBufferOnlyLineNeedRefresh = TRUE; + + // + // when is insert mode, or cursor is at end of this line, + // so insert this character + // or replace the character. + // + FilePos = FileBuffer.FilePosition.Column - 1; + if (FileBuffer.ModeInsert || FilePos + 1 > Line->Size) { + LineStrInsert (Line, Char, FilePos, Line->Size + 1); + } else { + Line->Buffer[FilePos] = Char; + } + // + // move cursor to right + // + FileBufferScrollRight (); + + if (!FileBuffer.FileModified) { + FileBuffer.FileModified = TRUE; + } + + return EFI_SUCCESS; +} + +/** + Handles inputs from characters (ASCII key + Backspace + return) + + @param[in] Char The input character. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR There was an error. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +FileBufferDoCharInput ( + IN CONST CHAR16 Char + ) +{ + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + switch (Char) { + case CHAR_NULL: + break; + + case CHAR_BACKSPACE: + Status = FileBufferDoBackspace (); + break; + + case CHAR_TAB: + // + // Tabs are ignored + // + break; + + case CHAR_LINEFEED: + case CHAR_CARRIAGE_RETURN: + Status = FileBufferDoReturn (); + break; + + default: + // + // DEAL WITH ASCII CHAR, filter out thing like ctrl+f + // + if (Char > 127 || Char < 32) { + Status = StatusBarSetStatusString (L"Unknown Command"); + } else { + Status = FileBufferAddChar (Char); + } + + break; + + } + + return Status; +} + +/** + Scroll cursor to the next line. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +FileBufferScrollDown ( + VOID + ) +{ + EFI_EDITOR_LINE *Line; + UINTN FRow; + UINTN FCol; + + Line = FileBuffer.CurrentLine; + if (Line->Buffer == NULL) { + return EFI_SUCCESS; + } + + FRow = FileBuffer.FilePosition.Row; + FCol = FileBuffer.FilePosition.Column; + + // + // has next line + // + if (Line->Link.ForwardLink != FileBuffer.ListHead) { + FRow++; + Line = CR (Line->Link.ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + + // + // if the next line is not that long, so move to end of next line + // + if (FCol > Line->Size) { + FCol = Line->Size + 1; + } + + } else { + return EFI_SUCCESS; + } + + FileBufferMovePosition (FRow, FCol); + + return EFI_SUCCESS; +} + +/** + Scroll the cursor to previous line. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +FileBufferScrollUp ( + VOID + ) +{ + EFI_EDITOR_LINE *Line; + UINTN FRow; + UINTN FCol; + + Line = FileBuffer.CurrentLine; + + FRow = FileBuffer.FilePosition.Row; + FCol = FileBuffer.FilePosition.Column; + + // + // has previous line + // + if (Line->Link.BackLink != FileBuffer.ListHead) { + FRow--; + Line = CR (Line->Link.BackLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + + // + // if previous line is not that long, so move to the end of previous line + // + if (FCol > Line->Size) { + FCol = Line->Size + 1; + } + + } else { + return EFI_SUCCESS; + } + + FileBufferMovePosition (FRow, FCol); + + return EFI_SUCCESS; +} + +/** + Scroll cursor to next page. + + @retval EFI_SUCCESS The operation wa successful. +**/ +EFI_STATUS +FileBufferPageDown ( + VOID + ) +{ + EFI_EDITOR_LINE *Line; + UINTN FRow; + UINTN FCol; + UINTN Gap; + + Line = FileBuffer.CurrentLine; + + FRow = FileBuffer.FilePosition.Row; + FCol = FileBuffer.FilePosition.Column; + + // + // has next page + // + if (FileBuffer.NumLines >= FRow + (MainEditor.ScreenSize.Row - 2)) { + Gap = (MainEditor.ScreenSize.Row - 2); + } else { + // + // MOVE CURSOR TO LAST LINE + // + Gap = FileBuffer.NumLines - FRow; + } + // + // get correct line + // + Line = MoveLine (Gap); + + // + // if that line, is not that long, so move to the end of that line + // + if (Line != NULL && FCol > Line->Size) { + FCol = Line->Size + 1; + } + + FRow += Gap; + + FileBufferMovePosition (FRow, FCol); + + return EFI_SUCCESS; +} + +/** + Scroll cursor to previous screen. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +FileBufferPageUp ( + VOID + ) +{ + EFI_EDITOR_LINE *Line; + UINTN FRow; + UINTN FCol; + UINTN Gap; + INTN Retreat; + + Line = FileBuffer.CurrentLine; + + FRow = FileBuffer.FilePosition.Row; + FCol = FileBuffer.FilePosition.Column; + + // + // has previous page + // + if (FRow > (MainEditor.ScreenSize.Row - 2)) { + Gap = (MainEditor.ScreenSize.Row - 2); + } else { + // + // the first line of file will displayed on the first line of screen + // + Gap = FRow - 1; + } + + Retreat = Gap; + Retreat = -Retreat; + + // + // get correct line + // + Line = MoveLine (Retreat); + + // + // if that line is not that long, so move to the end of that line + // + if (Line != NULL && FCol > Line->Size) { + FCol = Line->Size + 1; + } + + FRow -= Gap; + + FileBufferMovePosition (FRow, FCol); + + return EFI_SUCCESS; +} + +/** + Scroll cursor to end of the current line. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +FileBufferEnd ( + VOID + ) +{ + EFI_EDITOR_LINE *Line; + UINTN FRow; + UINTN FCol; + + Line = FileBuffer.CurrentLine; + + FRow = FileBuffer.FilePosition.Row; + + // + // goto the last column of the line + // + FCol = Line->Size + 1; + + FileBufferMovePosition (FRow, FCol); + + return EFI_SUCCESS; +} + +/** + Dispatch input to different handler + @param[in] Key The input key. One of: + ASCII KEY + Backspace/Delete + Return + Direction key: up/down/left/right/pgup/pgdn + Home/End + INS + + @retval EFI_SUCCESS The dispatch was done successfully. + @retval EFI_LOAD_ERROR The dispatch was not successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +FileBufferHandleInput ( + IN CONST EFI_INPUT_KEY *Key + ) +{ + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + switch (Key->ScanCode) { + // + // ordinary key input + // + case SCAN_NULL: + if (!FileBuffer.ReadOnly) { + Status = FileBufferDoCharInput (Key->UnicodeChar); + } else { + Status = StatusBarSetStatusString (L"Read Only File Can Not Be Modified"); + } + + break; + + // + // up arrow + // + case SCAN_UP: + Status = FileBufferScrollUp (); + break; + + // + // down arrow + // + case SCAN_DOWN: + Status = FileBufferScrollDown (); + break; + + // + // right arrow + // + case SCAN_RIGHT: + Status = FileBufferScrollRight (); + break; + + // + // left arrow + // + case SCAN_LEFT: + Status = FileBufferScrollLeft (); + break; + + // + // page up + // + case SCAN_PAGE_UP: + Status = FileBufferPageUp (); + break; + + // + // page down + // + case SCAN_PAGE_DOWN: + Status = FileBufferPageDown (); + break; + + // + // delete + // + case SCAN_DELETE: + if (!FileBuffer.ReadOnly) { + Status = FileBufferDoDelete (); + } else { + Status = StatusBarSetStatusString (L"Read Only File Can Not Be Modified"); + } + + break; + + // + // home + // + case SCAN_HOME: + FileBufferMovePosition (FileBuffer.FilePosition.Row, 1); + Status = EFI_SUCCESS; + break; + + // + // end + // + case SCAN_END: + Status = FileBufferEnd (); + break; + + // + // insert + // + case SCAN_INSERT: + FileBuffer.ModeInsert = (BOOLEAN)!FileBuffer.ModeInsert; + Status = EFI_SUCCESS; + break; + + default: + Status = StatusBarSetStatusString (L"Unknown Command"); + break; + } + + return Status; +} + +/** + Check user specified FileRow is above current screen. + + @param[in] FileRow The row of file position ( start from 1 ). + + @retval TRUE It is above the current screen. + @retval FALSE It is not above the current screen. +**/ +BOOLEAN +AboveCurrentScreen ( + IN UINTN FileRow + ) +{ + // + // if is to the above of the screen + // + if (FileRow < FileBuffer.LowVisibleRange.Row) { + return TRUE; + } + + return FALSE; +} + +/** + Check user specified FileRow is under current screen. + + @param[in] FileRow The row of file position ( start from 1 ). + + @retval TRUE It is under the current screen. + @retval FALSE It is not under the current screen. +**/ +BOOLEAN +UnderCurrentScreen ( + IN UINTN FileRow + ) +{ + // + // if is to the under of the screen + // + if (FileRow > FileBuffer.LowVisibleRange.Row + (MainEditor.ScreenSize.Row - 2) - 1) { + return TRUE; + } + + return FALSE; +} + +/** + Check user specified FileCol is left to current screen. + + @param[in] FileCol The column of file position ( start from 1 ). + + @retval TRUE It is to the left. + @retval FALSE It is not to the left. +**/ +BOOLEAN +LeftCurrentScreen ( + IN UINTN FileCol + ) +{ + // + // if is to the left of the screen + // + if (FileCol < FileBuffer.LowVisibleRange.Column) { + return TRUE; + } + + return FALSE; +} + +/** + Check user specified FileCol is right to current screen. + + @param[in] FileCol The column of file position ( start from 1 ). + + @retval TRUE It is to the right. + @retval FALSE It is not to the right. +**/ +BOOLEAN +RightCurrentScreen ( + IN UINTN FileCol + ) +{ + // + // if is to the right of the screen + // + if (FileCol > FileBuffer.LowVisibleRange.Column + MainEditor.ScreenSize.Column - 1) { + return TRUE; + } + + return FALSE; +} + +/** + Advance/Retreat lines and set CurrentLine in FileBuffer to it + + @param[in] Count The line number to advance/retreat + >0 : advance + <0: retreat + + @retval NULL An error occurred. + @return The line after advance/retreat. +**/ +EFI_EDITOR_LINE * +MoveCurrentLine ( + IN INTN Count + ) +{ + EFI_EDITOR_LINE *Line; + UINTN AbsCount; + + if (Count <= 0) { + AbsCount = (UINTN)ABS(Count); + Line = InternalEditorMiscLineRetreat (AbsCount,MainEditor.FileBuffer->CurrentLine,MainEditor.FileBuffer->ListHead); + } else { + Line = InternalEditorMiscLineAdvance ((UINTN)Count,MainEditor.FileBuffer->CurrentLine,MainEditor.FileBuffer->ListHead); + } + + if (Line == NULL) { + return NULL; + } + + MainEditor.FileBuffer->CurrentLine = Line; + + return Line; +} + +/** + According to cursor's file position, adjust screen display + + @param[in] NewFilePosRow The row of file position ( start from 1 ). + @param[in] NewFilePosCol The column of file position ( start from 1 ). +**/ +VOID +FileBufferMovePosition ( + IN CONST UINTN NewFilePosRow, + IN CONST UINTN NewFilePosCol + ) +{ + INTN RowGap; + INTN ColGap; + UINTN Abs; + BOOLEAN Above; + BOOLEAN Under; + BOOLEAN Right; + BOOLEAN Left; + + // + // CALCULATE gap between current file position and new file position + // + RowGap = NewFilePosRow - FileBuffer.FilePosition.Row; + ColGap = NewFilePosCol - FileBuffer.FilePosition.Column; + + Under = UnderCurrentScreen (NewFilePosRow); + Above = AboveCurrentScreen (NewFilePosRow); + // + // if is below current screen + // + if (Under) { + // + // display row will be unchanged + // + FileBuffer.FilePosition.Row = NewFilePosRow; + } else { + if (Above) { + // + // has enough above line, so display row unchanged + // not has enough above lines, so the first line is at the + // first display line + // + if (NewFilePosRow < (FileBuffer.DisplayPosition.Row - 1)) { + FileBuffer.DisplayPosition.Row = NewFilePosRow + 1; + } + + FileBuffer.FilePosition.Row = NewFilePosRow; + } else { + // + // in current screen + // + FileBuffer.FilePosition.Row = NewFilePosRow; + if (RowGap < 0) { + Abs = (UINTN)ABS(RowGap); + FileBuffer.DisplayPosition.Row -= Abs; + } else { + FileBuffer.DisplayPosition.Row += RowGap; + } + } + } + + FileBuffer.LowVisibleRange.Row = FileBuffer.FilePosition.Row - (FileBuffer.DisplayPosition.Row - 2); + + Right = RightCurrentScreen (NewFilePosCol); + Left = LeftCurrentScreen (NewFilePosCol); + + // + // if right to current screen + // + if (Right) { + // + // display column will be changed to end + // + FileBuffer.DisplayPosition.Column = MainEditor.ScreenSize.Column; + FileBuffer.FilePosition.Column = NewFilePosCol; + } else { + if (Left) { + // + // has enough left characters , so display row unchanged + // not has enough left characters, + // so the first character is at the first display column + // + if (NewFilePosCol < (FileBuffer.DisplayPosition.Column)) { + FileBuffer.DisplayPosition.Column = NewFilePosCol; + } + + FileBuffer.FilePosition.Column = NewFilePosCol; + } else { + // + // in current screen + // + FileBuffer.FilePosition.Column = NewFilePosCol; + if (ColGap < 0) { + Abs = (UINTN)(-ColGap); + FileBuffer.DisplayPosition.Column -= Abs; + } else { + FileBuffer.DisplayPosition.Column += ColGap; + } + } + } + + FileBuffer.LowVisibleRange.Column = FileBuffer.FilePosition.Column - (FileBuffer.DisplayPosition.Column - 1); + + // + // let CurrentLine point to correct line; + // + FileBuffer.CurrentLine = MoveCurrentLine (RowGap); + +} + +/** + Cut current line out and return a pointer to it. + + @param[out] CutLine Upon a successful return pointer to the pointer to + the allocated cut line. + + @retval EFI_SUCCESS The cut was successful. + @retval EFI_NOT_FOUND There was no selection to cut. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +FileBufferCutLine ( + OUT EFI_EDITOR_LINE **CutLine + ) +{ + EFI_EDITOR_LINE *Line; + EFI_EDITOR_LINE *NewLine; + UINTN Row; + UINTN Col; + + *CutLine = NULL; + + if (FileBuffer.ReadOnly) { + StatusBarSetStatusString (L"Read Only File Can Not Be Modified"); + return EFI_SUCCESS; + } + + Line = FileBuffer.CurrentLine; + + // + // if is the last dummy line, SO CAN not cut + // + if (StrCmp (Line->Buffer, L"\0") == 0 && Line->Link.ForwardLink == FileBuffer.ListHead + // + // last line + // + ) { + // + // LAST LINE AND NOTHING ON THIS LINE, SO CUT NOTHING + // + StatusBarSetStatusString (L"Nothing to Cut"); + return EFI_NOT_FOUND; + } + // + // if is the last line, so create a dummy line + // + if (Line->Link.ForwardLink == FileBuffer.ListHead) { + // + // last line + // create a new line + // + NewLine = FileBufferCreateLine (); + if (NewLine == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + FileBuffer.NumLines--; + Row = FileBuffer.FilePosition.Row; + Col = 1; + // + // move home + // + FileBuffer.CurrentLine = CR ( + FileBuffer.CurrentLine->Link.ForwardLink, + EFI_EDITOR_LINE, + Link, + LINE_LIST_SIGNATURE + ); + + RemoveEntryList (&Line->Link); + + FileBuffer.Lines = CR (FileBuffer.ListHead->ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + + FileBufferMovePosition (Row, Col); + + FileBuffer.FileModified = TRUE; + FileBufferNeedRefresh = TRUE; + FileBufferOnlyLineNeedRefresh = FALSE; + + *CutLine = Line; + + return EFI_SUCCESS; +} + +/** + Paste a line into line list. + + @retval EFI_SUCCESS The paste was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +FileBufferPasteLine ( + VOID + ) +{ + EFI_EDITOR_LINE *Line; + EFI_EDITOR_LINE *NewLine; + UINTN Row; + UINTN Col; + + // + // if nothing is on clip board + // then do nothing + // + if (MainEditor.CutLine == NULL) { + return EFI_SUCCESS; + } + // + // read only file can not be pasted on + // + if (FileBuffer.ReadOnly) { + StatusBarSetStatusString (L"Read Only File Can Not Be Modified"); + return EFI_SUCCESS; + } + + NewLine = LineDup (MainEditor.CutLine); + if (NewLine == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // insert it above current line + // + Line = FileBuffer.CurrentLine; + NewLine->Link.BackLink = Line->Link.BackLink; + NewLine->Link.ForwardLink = &Line->Link; + + Line->Link.BackLink->ForwardLink = &NewLine->Link; + Line->Link.BackLink = &NewLine->Link; + + FileBuffer.NumLines++; + FileBuffer.CurrentLine = NewLine; + + FileBuffer.Lines = CR (FileBuffer.ListHead->ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + + Col = 1; + // + // move home + // + Row = FileBuffer.FilePosition.Row; + + FileBufferMovePosition (Row, Col); + + // + // after paste, set some value so that refresh knows to do something + // + FileBuffer.FileModified = TRUE; + FileBufferNeedRefresh = TRUE; + FileBufferOnlyLineNeedRefresh = FALSE; + + return EFI_SUCCESS; +} + +/** + Search string from current position on in file + + @param[in] Str The search string. + @param[in] Offset The offset from current position. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_NOT_FOUND The string Str was not found. +**/ +EFI_STATUS +FileBufferSearch ( + IN CONST CHAR16 *Str, + IN CONST UINTN Offset + ) +{ + CHAR16 *Current; + UINTN Position; + UINTN Row; + UINTN Column; + EFI_EDITOR_LINE *Line; + CHAR16 *CharPos; + LIST_ENTRY *Link; + BOOLEAN Found; + + Column = 0; + Position = 0; + + // + // search if in current line + // + Current = FileBuffer.CurrentLine->Buffer + FileBuffer.FilePosition.Column - 1 + Offset; + + if (Current >= (FileBuffer.CurrentLine->Buffer + FileBuffer.CurrentLine->Size)) { + // + // the end + // + Current = FileBuffer.CurrentLine->Buffer + FileBuffer.CurrentLine->Size; + } + + Found = FALSE; + + CharPos = StrStr (Current, Str); + if (CharPos != NULL) { + Position = CharPos - Current + 1; + Found = TRUE; + } + + // + // found + // + if (Found) { + Column = (Position - 1) + FileBuffer.FilePosition.Column + Offset; + Row = FileBuffer.FilePosition.Row; + } else { + // + // not found so find through next lines + // + Link = FileBuffer.CurrentLine->Link.ForwardLink; + + Row = FileBuffer.FilePosition.Row + 1; + while (Link != FileBuffer.ListHead) { + Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); +// Position = StrStr (Line->Buffer, Str); + CharPos = StrStr (Line->Buffer, Str); + if (CharPos != NULL) { + Position = CharPos - Line->Buffer + 1; + Found = TRUE; + } + + if (Found) { + // + // found + // + Column = Position; + break; + } + + Row++; + Link = Link->ForwardLink; + } + + if (Link == FileBuffer.ListHead) { + Found = FALSE; + } else { + Found = TRUE; + } + } + + if (!Found) { + return EFI_NOT_FOUND; + } + + FileBufferMovePosition (Row, Column); + + // + // call refresh to fresh edit area, + // because the outer may loop to find multiply occurrence of this string + // + FileBufferRefresh (); + + return EFI_SUCCESS; +} + +/** + Replace SearchLen characters from current position on with Replace. + + This will modify the current buffer at the current position. + + @param[in] Replace The string to replace. + @param[in] SearchLen Search string's length. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +FileBufferReplace ( + IN CONST CHAR16 *Replace, + IN CONST UINTN SearchLen + ) +{ + UINTN ReplaceLen; + UINTN Index; + CHAR16 *Buffer; + UINTN NewSize; + UINTN OldSize; + UINTN Gap; + + ReplaceLen = StrLen (Replace); + + OldSize = FileBuffer.CurrentLine->Size + 1; + // + // include CHAR_NULL + // + NewSize = OldSize + (ReplaceLen - SearchLen); + + if (ReplaceLen > SearchLen) { + // + // do not have the enough space + // + if (FileBuffer.CurrentLine->TotalSize + 1 <= NewSize) { + FileBuffer.CurrentLine->Buffer = ReallocatePool ( + 2 * OldSize, + 2 * NewSize, + FileBuffer.CurrentLine->Buffer + ); + FileBuffer.CurrentLine->TotalSize = NewSize - 1; + } + + if (FileBuffer.CurrentLine->Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // the end CHAR_NULL character; + // + Buffer = FileBuffer.CurrentLine->Buffer + (NewSize - 1); + Gap = ReplaceLen - SearchLen; + + // + // keep the latter part + // + for (Index = 0; Index < (FileBuffer.CurrentLine->Size - FileBuffer.FilePosition.Column - SearchLen + 2); Index++) { + *Buffer = *(Buffer - Gap); + Buffer--; + } + // + // set replace into it + // + Buffer = FileBuffer.CurrentLine->Buffer + FileBuffer.FilePosition.Column - 1; + for (Index = 0; Index < ReplaceLen; Index++) { + Buffer[Index] = Replace[Index]; + } + } + + if (ReplaceLen < SearchLen) { + Buffer = FileBuffer.CurrentLine->Buffer + FileBuffer.FilePosition.Column - 1; + + for (Index = 0; Index < ReplaceLen; Index++) { + Buffer[Index] = Replace[Index]; + } + + Buffer += ReplaceLen; + Gap = SearchLen - ReplaceLen; + + // + // set replace into it + // + for (Index = 0; Index < (FileBuffer.CurrentLine->Size - FileBuffer.FilePosition.Column - ReplaceLen + 2); Index++) { + *Buffer = *(Buffer + Gap); + Buffer++; + } + } + + if (ReplaceLen == SearchLen) { + Buffer = FileBuffer.CurrentLine->Buffer + FileBuffer.FilePosition.Column - 1; + for (Index = 0; Index < ReplaceLen; Index++) { + Buffer[Index] = Replace[Index]; + } + } + + FileBuffer.CurrentLine->Size += (ReplaceLen - SearchLen); + + FileBufferOnlyLineNeedRefresh = TRUE; + + FileBuffer.FileModified = TRUE; + + MainTitleBarRefresh (MainEditor.FileBuffer->FileName, MainEditor.FileBuffer->FileType, MainEditor.FileBuffer->ReadOnly, MainEditor.FileBuffer->FileModified, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row, 0, 0); + FileBufferRestorePosition (); + FileBufferRefresh (); + + return EFI_SUCCESS; +} + +/** + Move the mouse cursor position. + + @param[in] TextX The new x-coordinate. + @param[in] TextY The new y-coordinate. +**/ +VOID +FileBufferAdjustMousePosition ( + IN CONST INT32 TextX, + IN CONST INT32 TextY + ) +{ + UINTN CoordinateX; + UINTN CoordinateY; + UINTN AbsX; + UINTN AbsY; + + // + // TextX and TextY is mouse movement data returned by mouse driver + // This function will change it to MousePosition + // + // + // get absolute value + // + + AbsX = ABS(TextX); + AbsY = ABS(TextY); + + CoordinateX = FileBuffer.MousePosition.Column; + CoordinateY = FileBuffer.MousePosition.Row; + + if (TextX >= 0) { + CoordinateX += TextX; + } else { + if (CoordinateX >= AbsX) { + CoordinateX -= AbsX; + } else { + CoordinateX = 0; + } + } + + if (TextY >= 0) { + CoordinateY += TextY; + } else { + if (CoordinateY >= AbsY) { + CoordinateY -= AbsY; + } else { + CoordinateY = 0; + } + } + // + // check whether new mouse column position is beyond screen + // if not, adjust it + // + if (CoordinateX >= 1 && CoordinateX <= MainEditor.ScreenSize.Column) { + FileBuffer.MousePosition.Column = CoordinateX; + } else if (CoordinateX < 1) { + FileBuffer.MousePosition.Column = 1; + } else if (CoordinateX > MainEditor.ScreenSize.Column) { + FileBuffer.MousePosition.Column = MainEditor.ScreenSize.Column; + } + // + // check whether new mouse row position is beyond screen + // if not, adjust it + // + if (CoordinateY >= 2 && CoordinateY <= (MainEditor.ScreenSize.Row - 1)) { + FileBuffer.MousePosition.Row = CoordinateY; + } else if (CoordinateY < 2) { + FileBuffer.MousePosition.Row = 2; + } else if (CoordinateY > (MainEditor.ScreenSize.Row - 1)) { + FileBuffer.MousePosition.Row = (MainEditor.ScreenSize.Row - 1); + } + +} + +/** + Search and replace operation. + + @param[in] SearchStr The string to search for. + @param[in] ReplaceStr The string to replace with. + @param[in] Offset The column to start at. +**/ +EFI_STATUS +FileBufferReplaceAll ( + IN CHAR16 *SearchStr, + IN CHAR16 *ReplaceStr, + IN UINTN Offset + ) +{ + CHAR16 *Buffer; + UINTN Position; + UINTN Column; + UINTN ReplaceLen; + UINTN SearchLen; + UINTN Index; + UINTN NewSize; + UINTN OldSize; + UINTN Gap; + EFI_EDITOR_LINE *Line; + LIST_ENTRY *Link; + CHAR16 *CharPos; + + SearchLen = StrLen (SearchStr); + ReplaceLen = StrLen (ReplaceStr); + + Column = FileBuffer.FilePosition.Column + Offset - 1; + + if (Column > FileBuffer.CurrentLine->Size) { + Column = FileBuffer.CurrentLine->Size; + } + + Link = &(FileBuffer.CurrentLine->Link); + + while (Link != FileBuffer.ListHead) { + Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + CharPos = StrStr (Line->Buffer + Column, SearchStr); + if (CharPos != NULL) { + Position = CharPos - Line->Buffer;// + Column; + // + // found + // + if (ReplaceLen > SearchLen) { + OldSize = Line->Size + 1; + // + // include CHAR_NULL + // + NewSize = OldSize + (ReplaceLen - SearchLen); + + // + // do not have the enough space + // + if (Line->TotalSize + 1 <= NewSize) { + Line->Buffer = ReallocatePool ( + 2 * OldSize, + 2 * NewSize, + Line->Buffer + ); + Line->TotalSize = NewSize - 1; + } + + if (Line->Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // the end CHAR_NULL character; + // + Buffer = Line->Buffer + (NewSize - 1); + Gap = ReplaceLen - SearchLen; + + // + // keep the latter part + // + for (Index = 0; Index < (Line->Size - Position - SearchLen + 1); Index++) { + *Buffer = *(Buffer - Gap); + Buffer--; + } + + } else if (ReplaceLen < SearchLen){ + Buffer = Line->Buffer + Position + ReplaceLen; + Gap = SearchLen - ReplaceLen; + + for (Index = 0; Index < (Line->Size - Position - ReplaceLen + 1); Index++) { + *Buffer = *(Buffer + Gap); + Buffer++; + } + } else { + ASSERT(ReplaceLen == SearchLen); + } + // + // set replace into it + // + Buffer = Line->Buffer + Position; + for (Index = 0; Index < ReplaceLen; Index++) { + Buffer[Index] = ReplaceStr[Index]; + } + + Line->Size += (ReplaceLen - SearchLen); + Column += ReplaceLen; + } else { + // + // not found + // + Column = 0; + Link = Link->ForwardLink; + } + } + // + // call refresh to fresh edit area + // + FileBuffer.FileModified = TRUE; + FileBufferNeedRefresh = TRUE; + FileBufferRefresh (); + + return EFI_SUCCESS; +} + +/** + Set the modified state to TRUE. +**/ +VOID +FileBufferSetModified ( + VOID + ) +{ + FileBuffer.FileModified = TRUE; +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.h new file mode 100644 index 00000000..c1da4d31 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.h @@ -0,0 +1,240 @@ +/** @file + Declares filebuffer interface functions. + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _LIB_FILE_BUFFER_H_ +#define _LIB_FILE_BUFFER_H_ + +#include "TextEditorTypes.h" + +/** + Initialization function for FileBuffer. + + @param EFI_SUCCESS The initialization was successful. + @param EFI_LOAD_ERROR A default name could not be created. + @param EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +FileBufferInit ( + VOID + ); + +/** + Cleanup function for FileBuffer. + + @retval EFI_SUCCESS The cleanup was successful. +**/ +EFI_STATUS +FileBufferCleanup ( + VOID + ); + +/** + Refresh the screen with whats in the buffer. + + @retval EFI_SUCCESS The refresh was successful. + @retval EFI_LOAD_ERROR There was an error finding what to write. +**/ +EFI_STATUS +FileBufferRefresh ( + VOID + ); + +/** + Dispatch input to different handler + @param[in] Key The input key. One of: + ASCII KEY + Backspace/Delete + Return + Direction key: up/down/left/right/pgup/pgdn + Home/End + INS + + @retval EFI_SUCCESS The dispatch was done successfully. + @retval EFI_LOAD_ERROR The dispatch was not successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +FileBufferHandleInput ( + IN CONST EFI_INPUT_KEY * Key + ); + +/** + Backup function for FileBuffer. Only backup the following items: + Mouse/Cursor position + File Name, Type, ReadOnly, Modified + Insert Mode + + This is for making the file buffer refresh as few as possible. + + @retval EFI_SUCCESS The backup operation was successful. +**/ +EFI_STATUS +FileBufferBackup ( + VOID + ); + +/** + Set the cursor position according to FileBuffer.DisplayPosition. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +FileBufferRestorePosition ( + VOID + ); + +/** + Set FileName field in FileBuffer. + + @param Str The file name to set. + + @retval EFI_SUCCESS The filename was successfully set. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_INVALID_PARAMETER Str is not a valid filename. +**/ +EFI_STATUS +FileBufferSetFileName ( + IN CONST CHAR16 *Str + ); + +/** + Read a file from disk into the FileBuffer. + + @param[in] FileName The filename to read. + @param[in] Recover TRUE if is for recover mode, no information printouts. + + @retval EFI_SUCCESS The load was successful. + @retval EFI_LOAD_ERROR The load failed. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_INVALID_PARAMETER FileName is a directory. +**/ +EFI_STATUS +FileBufferRead ( + IN CONST CHAR16 *FileName, + IN CONST BOOLEAN Recover + ); + +/** + Save lines in FileBuffer to disk + + @param[in] FileName The file name for writing. + + @retval EFI_SUCCESS Data was written. + @retval EFI_LOAD_ERROR + @retval EFI_OUT_OF_RESOURCES There were not enough resources to write the file. +**/ +EFI_STATUS +FileBufferSave ( + CONST CHAR16 *FileName + ); + +/** + According to cursor's file position, adjust screen display + + @param[in] NewFilePosRow The row of file position ( start from 1 ). + @param[in] NewFilePosCol The column of file position ( start from 1 ). +**/ +VOID +FileBufferMovePosition ( + IN CONST UINTN NewFilePosRow, + IN CONST UINTN NewFilePosCol + ); + +/** + Cut current line out and return a pointer to it. + + @param[out] CutLine Upon a successful return pointer to the pointer to + the allocated cut line. + + @retval EFI_SUCCESS The cut was successful. + @retval EFI_NOT_FOUND There was no selection to cut. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +FileBufferCutLine ( + OUT EFI_EDITOR_LINE **CutLine + ); + +/** + Paste a line into line list. + + @retval EFI_SUCCESS The paste was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +FileBufferPasteLine ( + VOID + ); + +/** + Search string from current position on in file + + @param[in] Str The search string. + @param[in] Offset The offset from current position. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_NOT_FOUND The string Str was not found. +**/ +EFI_STATUS +FileBufferSearch ( + IN CONST CHAR16 *Str, + IN CONST UINTN Offset + ); + +/** + Replace SearchLen characters from current position on with Replace. + + This will modify the current buffer at the current position. + + @param[in] Replace The string to replace. + @param[in] SearchLen Search string's length. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +FileBufferReplace ( + IN CONST CHAR16 *Replace, + IN CONST UINTN SearchLen + ); + +/** + Search and replace operation. + + @param[in] SearchStr The string to search for. + @param[in] ReplaceStr The string to replace with. + @param[in] Offset The column to start at. +**/ +EFI_STATUS +FileBufferReplaceAll ( + IN CHAR16 *SearchStr, + IN CHAR16 *ReplaceStr, + IN UINTN Offset + ); + +/** + Move the mouse cursor position. + + @param[in] TextX The new x-coordinate. + @param[in] TextY The new y-coordinate. +**/ +VOID +FileBufferAdjustMousePosition ( + IN CONST INT32 TextX, + IN CONST INT32 TextY + ); + +/** + Set the modified state to TRUE. +**/ +VOID +FileBufferSetModified ( + VOID + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.c new file mode 100644 index 00000000..3c3c587d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.c @@ -0,0 +1,1974 @@ +/** @file + Implements editor interface functions. + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "TextEditor.h" +#include "EditStatusBar.h" +#include "EditInputBar.h" +#include "EditMenuBar.h" + +// +// the first time editor launch +// +BOOLEAN EditorFirst; + +// +// it's time editor should exit +// +BOOLEAN EditorExit; + +BOOLEAN EditorMouseAction; + +extern EFI_EDITOR_FILE_BUFFER FileBuffer; + +extern BOOLEAN FileBufferNeedRefresh; + +extern BOOLEAN FileBufferOnlyLineNeedRefresh; + +extern BOOLEAN FileBufferMouseNeedRefresh; + +extern EFI_EDITOR_FILE_BUFFER FileBufferBackupVar; + +EFI_EDITOR_GLOBAL_EDITOR MainEditor; + + +/** + Load a file from disk to editor + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A load error occurred. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +MainCommandOpenFile ( + VOID + ); + +/** + Switch a file from ASCII to UNICODE or vise-versa. + + @retval EFI_SUCCESS The switch was ok or a warning was presented. +**/ +EFI_STATUS +MainCommandSwitchFileType ( + VOID + ); + +/** + move cursor to specified lines + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +MainCommandGotoLine ( + VOID + ); + +/** + Save current file to disk, you can save to current file name or + save to another file name. + + @retval EFI_SUCCESS The file was saved correctly. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A file access error occurred. +**/ +EFI_STATUS +MainCommandSaveFile ( + VOID + ); + +/** + Show help information for the editor. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +MainCommandDisplayHelp ( + VOID + ); + +/** + exit editor + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +MainCommandExit ( + VOID + ); + +/** + search string in file buffer + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +MainCommandSearch ( + VOID + ); + +/** + search string in file buffer, and replace it with another str + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +MainCommandSearchReplace ( + VOID + ); + +/** + cut current line to clipboard + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +MainCommandCutLine ( + VOID + ); + +/** + paste line to file buffer. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +MainCommandPasteLine ( + VOID + ); + +/** + Help info that will be displayed. +**/ +EFI_STRING_ID MainMenuHelpInfo[] = { + STRING_TOKEN(STR_EDIT_HELP_TITLE), + STRING_TOKEN(STR_EDIT_HELP_BLANK), + STRING_TOKEN(STR_EDIT_HELP_LIST_TITLE), + STRING_TOKEN(STR_EDIT_HELP_DIV), + STRING_TOKEN(STR_EDIT_HELP_GO_TO_LINE), + STRING_TOKEN(STR_EDIT_HELP_SAVE_FILE), + STRING_TOKEN(STR_EDIT_HELP_EXIT), + STRING_TOKEN(STR_EDIT_HELP_SEARCH), + STRING_TOKEN(STR_EDIT_HELP_SEARCH_REPLACE), + STRING_TOKEN(STR_EDIT_HELP_CUT_LINE), + STRING_TOKEN(STR_EDIT_HELP_PASTE_LINE), + STRING_TOKEN(STR_EDIT_HELP_OPEN_FILE), + STRING_TOKEN(STR_EDIT_HELP_FILE_TYPE), + STRING_TOKEN(STR_EDIT_HELP_BLANK), + STRING_TOKEN(STR_EDIT_HELP_EXIT_HELP), + STRING_TOKEN(STR_EDIT_HELP_BLANK), + STRING_TOKEN(STR_EDIT_HELP_BLANK), + STRING_TOKEN(STR_EDIT_HELP_BLANK), + STRING_TOKEN(STR_EDIT_HELP_BLANK), + STRING_TOKEN(STR_EDIT_HELP_BLANK), + STRING_TOKEN(STR_EDIT_HELP_BLANK), + STRING_TOKEN(STR_EDIT_HELP_BLANK), + STRING_TOKEN(STR_EDIT_HELP_DIV), +0 +}; + +MENU_ITEM_FUNCTION MainControlBasedMenuFunctions[] = { + NULL, + NULL, /* Ctrl - A */ + NULL, /* Ctrl - B */ + NULL, /* Ctrl - C */ + NULL, /* Ctrl - D */ + MainCommandDisplayHelp, /* Ctrl - E */ + MainCommandSearch, /* Ctrl - F */ + MainCommandGotoLine, /* Ctrl - G */ + NULL, /* Ctrl - H */ + NULL, /* Ctrl - I */ + NULL, /* Ctrl - J */ + MainCommandCutLine, /* Ctrl - K */ + NULL, /* Ctrl - L */ + NULL, /* Ctrl - M */ + NULL, /* Ctrl - N */ + MainCommandOpenFile, /* Ctrl - O */ + NULL, /* Ctrl - P */ + MainCommandExit, /* Ctrl - Q */ + MainCommandSearchReplace, /* Ctrl - R */ + MainCommandSaveFile, /* Ctrl - S */ + MainCommandSwitchFileType, /* Ctrl - T */ + MainCommandPasteLine, /* Ctrl - U */ + NULL, /* Ctrl - V */ + NULL, /* Ctrl - W */ + NULL, /* Ctrl - X */ + NULL, /* Ctrl - Y */ + NULL, /* Ctrl - Z */ +}; + +EDITOR_MENU_ITEM MainMenuItems[] = { + { + STRING_TOKEN(STR_EDIT_LIBMENUBAR_GO_TO_LINE), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F1), + MainCommandGotoLine + }, + { + STRING_TOKEN(STR_EDIT_LIBMENUBAR_SAVE_FILE), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F2), + MainCommandSaveFile + }, + { + STRING_TOKEN(STR_EDIT_LIBMENUBAR_EXIT), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F3), + MainCommandExit + }, + + { + STRING_TOKEN(STR_EDIT_LIBMENUBAR_SEARCH), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F4), + MainCommandSearch + }, + { + STRING_TOKEN(STR_EDIT_LIBMENUBAR_SEARCH_REPLACE), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F5), + MainCommandSearchReplace + }, + { + STRING_TOKEN(STR_EDIT_LIBMENUBAR_CUT_LINE), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F6), + MainCommandCutLine + }, + { + STRING_TOKEN(STR_EDIT_LIBMENUBAR_PASTE_LINE), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F7), + MainCommandPasteLine + }, + + { + STRING_TOKEN(STR_EDIT_LIBMENUBAR_OPEN_FILE), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F8), + MainCommandOpenFile + }, + { + STRING_TOKEN(STR_EDIT_LIBMENUBAR_FILE_TYPE), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F9), + MainCommandSwitchFileType + }, + { + STRING_TOKEN(STR_EDIT_LIBMENUBAR_FILE_TYPE), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F11), + MainCommandSwitchFileType + }, + + { + 0, + 0, + NULL + } +}; + + +/** + Load a file from disk to editor + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A load error occurred. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +MainCommandOpenFile ( + VOID + ) +{ + BOOLEAN Done; + EFI_STATUS Status; + + // + // This command will open a file from current working directory. + // Read-only file can also be opened. But it can not be modified. + // Below is the scenario of Open File command: + // 1.IF currently opened file has not been modIFied, directly go to step . + // IF currently opened file has been modified, + // an Input Bar will be prompted as : + // "File Modified. Save ( Yes/No/Cancel) ?" + // IF user press 'y' or 'Y', currently opened file will be saved. + // IF user press 'n' or 'N', currently opened file will + // not be saved. + // IF user press 'c' or 'C' or ESC, Open File command ends and + // currently opened file is still opened. + // + // 2. An Input Bar will be prompted as : "File Name to Open: " + // IF user press ESC, Open File command ends and + // currently opened file is still opened. + // Any other inputs with a Return will + // cause currently opened file close. + // + // 3. IF user input file name is an existing file , this file will be read + // and opened. + // IF user input file name is a new file, this file will be created + // and opened. This file's type ( UNICODE or ASCII ) is the same + // with the old file. + // if current file is modified, so you need to choose + // whether to save it first. + // + if (MainEditor.FileBuffer->FileModified) { + + Status = InputBarSetPrompt (L"File modified. Save (Yes/No/Cancel) ? "); + if (EFI_ERROR (Status)) { + return Status; + } + // + // the answer is just one character + // + Status = InputBarSetStringSize (1); + if (EFI_ERROR (Status)) { + return Status; + } + // + // loop for user's answer + // valid answer is just 'y' 'Y', 'n' 'N', 'c' 'C' + // + Done = FALSE; + while (!Done) { + Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); + StatusBarSetRefresh(); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + + switch (InputBarGetString()[0]) { + case L'y': + case L'Y': + // + // want to save this file first + // + Status = FileBufferSave (MainEditor.FileBuffer->FileName); + if (EFI_ERROR (Status)) { + return Status; + } + + MainTitleBarRefresh (MainEditor.FileBuffer->FileName, MainEditor.FileBuffer->FileType, MainEditor.FileBuffer->ReadOnly, MainEditor.FileBuffer->FileModified, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row, 0, 0); + FileBufferRestorePosition (); + Done = TRUE; + break; + + case L'n': + case L'N': + // + // the file won't be saved + // + Done = TRUE; + break; + + case L'c': + case L'C': + return EFI_SUCCESS; + } + } + } + // + // TO get the open file name + // + Status = InputBarSetPrompt (L"File Name to Open: "); + if (EFI_ERROR (Status)) { + FileBufferRead (MainEditor.FileBuffer->FileName, TRUE); + return Status; + } + + Status = InputBarSetStringSize (100); + if (EFI_ERROR (Status)) { + FileBufferRead (MainEditor.FileBuffer->FileName, TRUE); + return Status; + } + + while (1) { + Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); + StatusBarSetRefresh(); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + // + // The input string length should > 0 + // + if (StrLen (InputBarGetString()) > 0) { + // + // CHECK if filename is valid + // + if (!IsValidFileName (InputBarGetString())) { + FileBufferRead (MainEditor.FileBuffer->FileName, TRUE); + StatusBarSetStatusString (L"Invalid File Name"); + return EFI_SUCCESS; + } + + break; + } + } + // + // read from disk + // + Status = FileBufferRead (InputBarGetString(), FALSE); + + if (EFI_ERROR (Status)) { + FileBufferRead (MainEditor.FileBuffer->FileName, TRUE); + return EFI_LOAD_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Switch a file from ASCII to UNICODE or vise-versa. + + @retval EFI_SUCCESS The switch was ok or a warning was presented. +**/ +EFI_STATUS +MainCommandSwitchFileType ( + VOID + ) +{ + // + // Below is the scenario of File Type command: + // After File Type is executed, file type will be changed to another type + // if file is read-only, can not be modified + // + if (MainEditor.FileBuffer->ReadOnly) { + StatusBarSetStatusString (L"Read Only File Can Not Be Modified"); + return EFI_SUCCESS; + } + + if (MainEditor.FileBuffer->FileType == FileTypeUnicode) { + MainEditor.FileBuffer->FileType = FileTypeAscii; + } else { + MainEditor.FileBuffer->FileType = FileTypeUnicode; + } + + MainEditor.FileBuffer->FileModified = TRUE; + + return EFI_SUCCESS; +} + +/** + cut current line to clipboard + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +MainCommandCutLine ( + VOID + ) +{ + EFI_STATUS Status; + EFI_EDITOR_LINE *Line; + + // + // This command will cut current line ( where cursor is on ) to clip board. + // And cursor will move to the beginning of next line. + // Below is the scenario of Cut Line command: + // 1. IF cursor is on valid line, current line will be cut to clip board. + // IF cursor is not on valid line, an Status String will be prompted : + // "Nothing to Cut". + // + Line = NULL; + Status = FileBufferCutLine (&Line); + if (Status == EFI_NOT_FOUND) { + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + MainEditor.CutLine = Line; + + return EFI_SUCCESS; +} + +/** + paste line to file buffer. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +MainCommandPasteLine ( + VOID + ) +{ + EFI_STATUS Status; + + // + // Below is the scenario of Paste Line command: + // 1. IF nothing is on clipboard, a Status String will be prompted : + // "No Line to Paste" and Paste Line command ends. + // IF something is on clipboard, insert it above current line. + // nothing on clipboard + // + if (MainEditor.CutLine == NULL) { + StatusBarSetStatusString (L"No Line to Paste"); + return EFI_SUCCESS; + } + + Status = FileBufferPasteLine (); + + return Status; +} + + +/** + search string in file buffer + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +MainCommandSearch ( + VOID + ) +{ + EFI_STATUS Status; + CHAR16 *Buffer; + BOOLEAN Done; + UINTN Offset; + + // + // Below is the scenario of Search command: + // 1. An Input Bar will be prompted : "Enter Search String:". + // IF user press ESC, Search command ends. + // IF user just press Enter, Search command ends. + // IF user inputs the search string, do Step 2. + // + // 2. IF input search string is found, cursor will move to the first + // occurrence and do Step 3. + // IF input search string is not found, a Status String + // "Search String Not Found" will be prompted and Search command ends. + // + // 3. An Input Bar will be prompted: "Find Next (Yes/No/Cancel ) ?". + // IF user press ESC, Search command ends. + // IF user press 'y' or 'Y', do Step 2. + // IF user press 'n' or 'N', Search command ends. + // IF user press 'c' or 'C', Search command ends. + // + Status = InputBarSetPrompt (L"Enter Search String: "); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarSetStringSize (40); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); + StatusBarSetRefresh(); + + // + // ESC + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + // + // just enter pressed + // + if (StrLen (InputBarGetString()) == 0) { + return EFI_SUCCESS; + } + + Buffer = CatSPrint (NULL, L"%s", InputBarGetString()); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // the first time , search from current position + // + Offset = 0; + do { + // + // since search may be continued to search multiple times + // so we need to backup editor each time + // + MainEditorBackup (); + + Status = FileBufferSearch (Buffer, Offset); + + if (Status == EFI_NOT_FOUND) { + break; + } + // + // Find next + // + Status = InputBarSetPrompt (L"Find Next (Yes/No) ?"); + if (EFI_ERROR (Status)) { + FreePool (Buffer); + return Status; + } + + Status = InputBarSetStringSize (1); + if (EFI_ERROR (Status)) { + FreePool (Buffer); + return Status; + } + + Done = FALSE; + while (!Done) { + Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); + StatusBarSetRefresh(); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + FreePool (Buffer); + return EFI_SUCCESS; + } + + switch (InputBarGetString()[0]) { + case L'y': + case L'Y': + Done = TRUE; + break; + + case L'n': + case L'N': + FreePool (Buffer); + return EFI_SUCCESS; + + } + // + // end of which + // + } + // + // end of while !Done + // for search second, third time, search from current position + strlen + // + Offset = StrLen (Buffer); + + } while (1); + // + // end of do + // + FreePool (Buffer); + StatusBarSetStatusString (L"Search String Not Found"); + + return EFI_SUCCESS; +} + +/** + Search string in file buffer, and replace it with another str. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +MainCommandSearchReplace ( + VOID + ) +{ + EFI_STATUS Status; + CHAR16 *Search; + CHAR16 *Replace; + BOOLEAN Done; + BOOLEAN First; + BOOLEAN ReplaceOption; + UINTN SearchLen; + UINTN ReplaceLen; + BOOLEAN ReplaceAll; + + ReplaceOption = FALSE; + + // + // Below is the scenario of Search/Replace command: + // 1. An Input Bar is prompted : "Enter Search String:". + // IF user press ESC, Search/Replace command ends. + // IF user just press Enter, Search/Replace command ends. + // IF user inputs the search string S, do Step 2. + // + // 2. An Input Bar is prompted: "Replace With:". + // IF user press ESC, Search/Replace command ends. + // IF user inputs the replace string R, do Step 3. + // + // 3. IF input search string is not found, an Status String + // "Search String Not Found" will be prompted + // and Search/Replace command ends + // IF input search string is found, do Step 4. + // + // 4. An Input Bar will be prompted: "Replace ( Yes/No/All/Cancel )?" + // IF user press 'y' or 'Y', S will be replaced with R and do Step 5 + // IF user press 'n' or 'N', S will not be replaced and do Step 5. + // IF user press 'a' or 'A', all the S from file current position on + // will be replaced with R and Search/Replace command ends. + // IF user press 'c' or 'C' or ESC, Search/Replace command ends. + // + // 5. An Input Bar will be prompted: "Find Next (Yes/No/Cancel) ?". + // IF user press ESC, Search/Replace command ends. + // IF user press 'y' or 'Y', do Step 3. + // IF user press 'n' or 'N', Search/Replace command ends. + // IF user press 'c' or 'C', Search/Replace command ends. + // input search string + // + Status = InputBarSetPrompt (L"Enter Search String: "); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarSetStringSize (40); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); + StatusBarSetRefresh(); + + // + // ESC + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + // + // if just pressed enter + // + if (StrLen (InputBarGetString()) == 0) { + return EFI_SUCCESS; + } + + Search = CatSPrint (NULL, L"%s", InputBarGetString()); + if (Search == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + SearchLen = StrLen (Search); + + // + // input replace string + // + Status = InputBarSetPrompt (L"Replace With: "); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarSetStringSize (40); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); + StatusBarSetRefresh(); + + // + // ESC + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + + Replace = CatSPrint (NULL, L"%s", InputBarGetString()); + if (Replace == NULL) { + FreePool (Search); + return EFI_OUT_OF_RESOURCES; + } + + ReplaceLen = StrLen (Replace); + + First = TRUE; + ReplaceAll = FALSE; + do { + // + // since search may be continued to search multiple times + // so we need to backup editor each time + // + MainEditorBackup (); + + if (First) { + Status = FileBufferSearch (Search, 0); + } else { + // + // if just replace, so skip this replace string + // if replace string is an empty string, so skip to next character + // + if (ReplaceOption) { + Status = FileBufferSearch (Search, (ReplaceLen == 0) ? 1 : ReplaceLen); + } else { + Status = FileBufferSearch (Search, SearchLen); + } + } + + if (Status == EFI_NOT_FOUND) { + break; + } + // + // replace or not? + // + Status = InputBarSetPrompt (L"Replace (Yes/No/All/Cancel) ?"); + + if (EFI_ERROR (Status)) { + FreePool (Search); + FreePool (Replace); + return Status; + } + + Status = InputBarSetStringSize (1); + if (EFI_ERROR (Status)) { + FreePool (Search); + FreePool (Replace); + return Status; + } + + Done = FALSE; + while (!Done) { + Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); + StatusBarSetRefresh(); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + FreePool (Search); + FreePool (Replace); + return EFI_SUCCESS; + } + + switch (InputBarGetString()[0]) { + case L'y': + case L'Y': + Done = TRUE; + ReplaceOption = TRUE; + break; + + case L'n': + case L'N': + Done = TRUE; + ReplaceOption = FALSE; + break; + + case L'a': + case L'A': + Done = TRUE; + ReplaceOption = TRUE; + ReplaceAll = TRUE; + break; + + case L'c': + case L'C': + FreePool (Search); + FreePool (Replace); + return EFI_SUCCESS; + + } + // + // end of which + // + } + // + // end of while !Done + // Decide to Replace + // + if (ReplaceOption) { + // + // file is read-only + // + if (MainEditor.FileBuffer->ReadOnly) { + StatusBarSetStatusString (L"Read Only File Can Not Be Modified"); + return EFI_SUCCESS; + } + // + // replace all + // + if (ReplaceAll) { + Status = FileBufferReplaceAll (Search, Replace, 0); + FreePool (Search); + FreePool (Replace); + return Status; + } + // + // replace + // + Status = FileBufferReplace (Replace, SearchLen); + if (EFI_ERROR (Status)) { + FreePool (Search); + FreePool (Replace); + return Status; + } + } + // + // Find next + // + Status = InputBarSetPrompt (L"Find Next (Yes/No) ?"); + if (EFI_ERROR (Status)) { + FreePool (Search); + FreePool (Replace); + return Status; + } + + Status = InputBarSetStringSize (1); + if (EFI_ERROR (Status)) { + FreePool (Search); + FreePool (Replace); + return Status; + } + + Done = FALSE; + while (!Done) { + Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); + StatusBarSetRefresh(); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + FreePool (Search); + FreePool (Replace); + return EFI_SUCCESS; + } + + switch (InputBarGetString()[0]) { + case L'y': + case L'Y': + Done = TRUE; + break; + + case L'n': + case L'N': + FreePool (Search); + FreePool (Replace); + return EFI_SUCCESS; + + } + // + // end of which + // + } + // + // end of while !Done + // + First = FALSE; + + } while (1); + // + // end of do + // + FreePool (Search); + FreePool (Replace); + + StatusBarSetStatusString (L"Search String Not Found"); + + return EFI_SUCCESS; +} + +/** + exit editor + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +MainCommandExit ( + VOID + ) +{ + EFI_STATUS Status; + + // + // Below is the scenario of Exit command: + // 1. IF currently opened file is not modified, exit the editor and + // Exit command ends. + // IF currently opened file is modified, do Step 2 + // + // 2. An Input Bar will be prompted: + // "File modified. Save ( Yes/No/Cancel )?" + // IF user press 'y' or 'Y', currently opened file will be saved + // and Editor exits + // IF user press 'n' or 'N', currently opened file will not be saved + // and Editor exits. + // IF user press 'c' or 'C' or ESC, Exit command ends. + // if file has been modified, so will prompt user whether to save the changes + // + if (MainEditor.FileBuffer->FileModified) { + + Status = InputBarSetPrompt (L"File modified. Save (Yes/No/Cancel) ? "); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarSetStringSize (1); + if (EFI_ERROR (Status)) { + return Status; + } + + while (1) { + Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); + StatusBarSetRefresh(); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + + switch (InputBarGetString()[0]) { + case L'y': + case L'Y': + // + // write file back to disk + // + Status = FileBufferSave (MainEditor.FileBuffer->FileName); + if (!EFI_ERROR (Status)) { + EditorExit = TRUE; + } + + return Status; + + case L'n': + case L'N': + EditorExit = TRUE; + return EFI_SUCCESS; + + case L'c': + case L'C': + return EFI_SUCCESS; + + } + } + } + + EditorExit = TRUE; + return EFI_SUCCESS; + +} + +/** + move cursor to specified lines + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +MainCommandGotoLine ( + VOID + ) +{ + EFI_STATUS Status; + UINTN Row; + + // + // Below is the scenario of Go To Line command: + // 1. An Input Bar will be prompted : "Go To Line:". + // IF user press ESC, Go To Line command ends. + // IF user just press Enter, cursor remains unchanged. + // IF user inputs line number, do Step 2. + // + // 2. IF input line number is valid, move cursor to the beginning + // of specified line and Go To Line command ends. + // IF input line number is invalid, a Status String will be prompted: + // "No Such Line" and Go To Line command ends. + // + Status = InputBarSetPrompt (L"Go To Line: "); + if (EFI_ERROR (Status)) { + return Status; + } + // + // line number's digit <= 6 + // + Status = InputBarSetStringSize (6); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); + StatusBarSetRefresh(); + + // + // press ESC + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + // + // if JUST press enter + // + if (StrLen (InputBarGetString()) == 0) { + return EFI_SUCCESS; + } + + Row = ShellStrToUintn (InputBarGetString()); + + // + // invalid line number + // + if (Row > MainEditor.FileBuffer->NumLines || Row <= 0) { + StatusBarSetStatusString (L"No Such Line"); + return EFI_SUCCESS; + } + // + // move cursor to that line's start + // + FileBufferMovePosition (Row, 1); + + return EFI_SUCCESS; +} + +/** + Save current file to disk, you can save to current file name or + save to another file name. + + @retval EFI_SUCCESS The file was saved correctly. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A file access error occurred. +**/ +EFI_STATUS +MainCommandSaveFile ( + VOID + ) +{ + EFI_STATUS Status; + CHAR16 *FileName; + BOOLEAN OldFile; + CHAR16 *Str; + SHELL_FILE_HANDLE FileHandle; + EFI_FILE_INFO *Info; + + // + // This command will save currently opened file to disk. + // You can choose save to another file name or just save to + // current file name. + // Below is the scenario of Save File command: + // ( Suppose the old file name is A ) + // 1. An Input Bar will be prompted: "File To Save: [ old file name]" + // IF user press ESC, Save File command ends . + // IF user press Enter, input file name will be A. + // IF user inputs a new file name B, input file name will be B. + // + // 2. IF input file name is A, go to do Step 3. + // IF input file name is B, go to do Step 4. + // + // 3. IF A is read only, Status Bar will show "Access Denied" and + // Save File commands ends. + // IF A is not read only, save file buffer to disk and remove modified + // flag in Title Bar , then Save File command ends. + // + // 4. IF B does not exist, create this file and save file buffer to it. + // Go to do Step 7. + // IF B exits, do Step 5. + // + // 5.An Input Bar will be prompted: + // "File Exists. Overwrite ( Yes/No/Cancel )?" + // IF user press 'y' or 'Y', do Step 6. + // IF user press 'n' or 'N', Save File commands ends. + // IF user press 'c' or 'C' or ESC, Save File commands ends. + // + // 6. IF B is a read-only file, Status Bar will show "Access Denied" and + // Save File commands ends. + // IF B can be read and write, save file buffer to B. + // + // 7. Update File Name field in Title Bar to B and remove the modified + // flag in Title Bar. + // + Str = CatSPrint (NULL, L"File to Save: [%s]", MainEditor.FileBuffer->FileName); + if (Str == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (StrLen (Str) >= 50) { + // + // replace the long file name with "..." + // + Str[46] = L'.'; + Str[47] = L'.'; + Str[48] = L'.'; + Str[49] = L']'; + Str[50] = CHAR_NULL; + } + + Status = InputBarSetPrompt (Str); + FreePool(Str); + + if (EFI_ERROR (Status)) { + return Status; + } + + + Status = InputBarSetStringSize (100); + if (EFI_ERROR (Status)) { + return Status; + } + // + // get new file name + // + Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); + StatusBarSetRefresh(); + + // + // if user pressed ESC + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + + // + // if just enter pressed, so think save to current file name + // + if (StrLen (InputBarGetString()) == 0) { + FileName = CatSPrint (NULL, L"%s", MainEditor.FileBuffer->FileName); + } else { + FileName = CatSPrint (NULL, L"%s", InputBarGetString()); + } + + if (FileName == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (!IsValidFileName (FileName)) { + StatusBarSetStatusString (L"Invalid File Name"); + FreePool (FileName); + return EFI_SUCCESS; + } + + OldFile = FALSE; + + // + // save to the old file + // + if (StringNoCaseCompare (&FileName, &MainEditor.FileBuffer->FileName) == 0) { + OldFile = TRUE; + } + + if (OldFile) { + // + // if the file is read only, so can not write back to it. + // + if (MainEditor.FileBuffer->ReadOnly == TRUE) { + StatusBarSetStatusString (L"Access Denied"); + FreePool (FileName); + return EFI_SUCCESS; + } + } else { + // + // if the file exists + // + if (ShellFileExists(FileName) != EFI_NOT_FOUND) { + // + // check for read only + // + Status = ShellOpenFileByName(FileName, &FileHandle, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR(Status)) { + StatusBarSetStatusString (L"Open Failed"); + FreePool (FileName); + return EFI_SUCCESS; + } + + Info = ShellGetFileInfo(FileHandle); + if (Info == NULL) { + StatusBarSetStatusString (L"Access Denied"); + FreePool (FileName); + return (EFI_SUCCESS); + } + + if (Info->Attribute & EFI_FILE_READ_ONLY) { + StatusBarSetStatusString (L"Access Denied - Read Only"); + FreePool (Info); + FreePool (FileName); + return (EFI_SUCCESS); + } + FreePool (Info); + + // + // ask user whether to overwrite this file + // + Status = InputBarSetPrompt (L"File exists. Overwrite (Yes/No/Cancel) ? "); + if (EFI_ERROR (Status)) { + SHELL_FREE_NON_NULL (FileName); + return Status; + } + + Status = InputBarSetStringSize (1); + if (EFI_ERROR (Status)) { + SHELL_FREE_NON_NULL (FileName); + return Status; + } + + while (TRUE) { + Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); + StatusBarSetRefresh(); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + SHELL_FREE_NON_NULL (FileName); + return EFI_SUCCESS; + } + + switch (InputBarGetString()[0]) { + case L'y': + case L'Y': + break; + + case L'n': + case L'N': + case L'c': + case L'C': + SHELL_FREE_NON_NULL (FileName); + return EFI_SUCCESS; + } // end switch + } // while (!done) + } // file does exist + } // if old file name same + + // + // save file to disk with specified name + // + FileBufferSetModified(); + Status = FileBufferSave (FileName); + SHELL_FREE_NON_NULL (FileName); + + return Status; +} + +/** + Show help information for the editor. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +MainCommandDisplayHelp ( + VOID + ) +{ + INT32 CurrentLine; + CHAR16 *InfoString; + EFI_KEY_DATA KeyData; + EFI_STATUS Status; + UINTN EventIndex; + + // + // print helpInfo + // + for (CurrentLine = 0; 0 != MainMenuHelpInfo[CurrentLine]; CurrentLine++) { + InfoString = HiiGetString(gShellDebug1HiiHandle, MainMenuHelpInfo[CurrentLine], NULL); + ShellPrintEx (0, CurrentLine+1, L"%E%s%N", InfoString); + } + + // + // scan for ctrl+w + // + while (TRUE) { + Status = gBS->WaitForEvent (1, &MainEditor.TextInputEx->WaitForKeyEx, &EventIndex); + if (EFI_ERROR (Status) || (EventIndex != 0)) { + continue; + } + Status = MainEditor.TextInputEx->ReadKeyStrokeEx (MainEditor.TextInputEx, &KeyData); + if (EFI_ERROR (Status)) { + continue; + } + + if (((KeyData.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) == 0) || + (KeyData.KeyState.KeyShiftState == EFI_SHIFT_STATE_VALID)) { + // + // For consoles that don't support/report shift state, + // CTRL+W is translated to L'W' - L'A' + 1. + // + if (KeyData.Key.UnicodeChar == L'W' - L'A' + 1) { + break; + } + } else if (((KeyData.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) && + ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) && + ((KeyData.KeyState.KeyShiftState & ~(EFI_SHIFT_STATE_VALID | EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) == 0)) { + // + // For consoles that supports/reports shift state, + // make sure that only CONTROL shift key is pressed. + // + if ((KeyData.Key.UnicodeChar == 'w') || (KeyData.Key.UnicodeChar == 'W')) { + break; + } + } + } + // + // update screen with file buffer's info + // + FileBufferRestorePosition (); + FileBufferNeedRefresh = TRUE; + FileBufferOnlyLineNeedRefresh = FALSE; + FileBufferRefresh (); + + return EFI_SUCCESS; +} + +EFI_EDITOR_COLOR_ATTRIBUTES OriginalColors; +INTN OriginalMode; + + +// +// basic initialization for MainEditor +// +EFI_EDITOR_GLOBAL_EDITOR MainEditorConst = { + &FileBuffer, + { + {0, 0} + }, + { + 0, + 0 + }, + NULL, + NULL, + FALSE, + NULL +}; + +/** + The initialization function for MainEditor. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +MainEditorInit ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN HandleCount; + UINTN Index; + + // + // basic initialization + // + CopyMem (&MainEditor, &MainEditorConst, sizeof (MainEditor)); + + // + // set screen attributes + // + MainEditor.ColorAttributes.Colors.Foreground = gST->ConOut->Mode->Attribute & 0x000000ff; + + MainEditor.ColorAttributes.Colors.Background = (UINT8) (gST->ConOut->Mode->Attribute >> 4); + OriginalColors = MainEditor.ColorAttributes.Colors; + + OriginalMode = gST->ConOut->Mode->Mode; + + // + // query screen size + // + gST->ConOut->QueryMode ( + gST->ConOut, + gST->ConOut->Mode->Mode, + &(MainEditor.ScreenSize.Column), + &(MainEditor.ScreenSize.Row) + ); + + // + // Find TextInEx in System Table ConsoleInHandle + // Per UEFI Spec, TextInEx is required for a console capable platform. + // + Status = gBS->HandleProtocol ( + gST->ConsoleInHandle, + &gEfiSimpleTextInputExProtocolGuid, + (VOID**)&MainEditor.TextInputEx + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Find mouse in System Table ConsoleInHandle + // + Status = gBS->HandleProtocol ( + gST->ConsoleInHandle, + &gEfiSimplePointerProtocolGuid, + (VOID**)&MainEditor.MouseInterface + ); + if (EFI_ERROR (Status)) { + // + // If there is no Simple Pointer Protocol on System Table + // + HandleBuffer = NULL; + MainEditor.MouseInterface = NULL; + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimplePointerProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (!EFI_ERROR (Status) && HandleCount > 0) { + // + // Try to find the first available mouse device + // + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiSimplePointerProtocolGuid, + (VOID**)&MainEditor.MouseInterface + ); + if (!EFI_ERROR (Status)) { + break; + } + } + } + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + } + + if (!EFI_ERROR (Status) && MainEditor.MouseInterface != NULL) { + MainEditor.MouseAccumulatorX = 0; + MainEditor.MouseAccumulatorY = 0; + MainEditor.MouseSupported = TRUE; + } + + // + // below will call the five components' init function + // + Status = MainTitleBarInit (L"UEFI EDIT"); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_TITLEBAR), gShellDebug1HiiHandle); + return EFI_LOAD_ERROR; + } + + Status = ControlHotKeyInit (MainControlBasedMenuFunctions); + Status = MenuBarInit (MainMenuItems); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_MAINMENU), gShellDebug1HiiHandle); + return EFI_LOAD_ERROR; + } + + Status = StatusBarInit (); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_STATUSBAR), gShellDebug1HiiHandle); + return EFI_LOAD_ERROR; + } + + InputBarInit (MainEditor.TextInputEx); + + Status = FileBufferInit (); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_FILEBUFFER), gShellDebug1HiiHandle); + return EFI_LOAD_ERROR; + } + // + // clear whole screen and enable cursor + // + gST->ConOut->ClearScreen (gST->ConOut); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + + // + // initialize EditorFirst and EditorExit + // + EditorFirst = TRUE; + EditorExit = FALSE; + EditorMouseAction = FALSE; + + return EFI_SUCCESS; +} + +/** + The cleanup function for MainEditor. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +MainEditorCleanup ( + VOID + ) +{ + EFI_STATUS Status; + + // + // call the five components' cleanup function + // if error, do not exit + // just print some warning + // + MainTitleBarCleanup(); + StatusBarCleanup(); + InputBarCleanup(); + MenuBarCleanup (); + + Status = FileBufferCleanup (); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_FILEBUFFER_CLEANUP), gShellDebug1HiiHandle); + } + // + // restore old mode + // + if (OriginalMode != gST->ConOut->Mode->Mode) { + gST->ConOut->SetMode (gST->ConOut, OriginalMode); + } + // + // restore old screen color + // + gST->ConOut->SetAttribute ( + gST->ConOut, + EFI_TEXT_ATTR (OriginalColors.Foreground, OriginalColors.Background) + ); + + gST->ConOut->ClearScreen (gST->ConOut); + + return EFI_SUCCESS; +} + +/** + Refresh the main editor component. +**/ +VOID +MainEditorRefresh ( + VOID + ) +{ + // + // The Stall value is from experience. NOT from spec. avoids 'flicker' + // + gBS->Stall (50); + + // + // call the components refresh function + // + if (EditorFirst + || StrCmp (FileBufferBackupVar.FileName, FileBuffer.FileName) != 0 + || FileBufferBackupVar.FileType != FileBuffer.FileType + || FileBufferBackupVar.FileModified != FileBuffer.FileModified + || FileBufferBackupVar.ReadOnly != FileBuffer.ReadOnly) { + + MainTitleBarRefresh (MainEditor.FileBuffer->FileName, MainEditor.FileBuffer->FileType, MainEditor.FileBuffer->ReadOnly, MainEditor.FileBuffer->FileModified, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row, 0, 0); + FileBufferRestorePosition (); + } + + if (EditorFirst + || FileBufferBackupVar.FilePosition.Row != FileBuffer.FilePosition.Row + || FileBufferBackupVar.FilePosition.Column != FileBuffer.FilePosition.Column + || FileBufferBackupVar.ModeInsert != FileBuffer.ModeInsert + || StatusBarGetRefresh()) { + + StatusBarRefresh (EditorFirst, MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column, MainEditor.FileBuffer->FilePosition.Row, MainEditor.FileBuffer->FilePosition.Column, MainEditor.FileBuffer->ModeInsert); + FileBufferRestorePosition (); + } + + if (EditorFirst) { + FileBufferRestorePosition (); + } + + FileBufferRefresh (); + + // + // EditorFirst is now set to FALSE + // + EditorFirst = FALSE; +} + +/** + Get's the resultant location of the cursor based on the relative movement of the Mouse. + + @param[in] GuidX The relative mouse movement. + + @return The X location of the mouse. +**/ +INT32 +GetTextX ( + IN INT32 GuidX + ) +{ + INT32 Gap; + + MainEditor.MouseAccumulatorX += GuidX; + Gap = (MainEditor.MouseAccumulatorX * (INT32) MainEditor.ScreenSize.Column) / (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionX); + MainEditor.MouseAccumulatorX = (MainEditor.MouseAccumulatorX * (INT32) MainEditor.ScreenSize.Column) % (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionX); + MainEditor.MouseAccumulatorX = MainEditor.MouseAccumulatorX / (INT32) MainEditor.ScreenSize.Column; + return Gap; +} + +/** + Get's the resultant location of the cursor based on the relative movement of the Mouse. + + @param[in] GuidY The relative mouse movement. + + @return The Y location of the mouse. +**/ +INT32 +GetTextY ( + IN INT32 GuidY + ) +{ + INT32 Gap; + + MainEditor.MouseAccumulatorY += GuidY; + Gap = (MainEditor.MouseAccumulatorY * (INT32) MainEditor.ScreenSize.Row) / (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionY); + MainEditor.MouseAccumulatorY = (MainEditor.MouseAccumulatorY * (INT32) MainEditor.ScreenSize.Row) % (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionY); + MainEditor.MouseAccumulatorY = MainEditor.MouseAccumulatorY / (INT32) MainEditor.ScreenSize.Row; + + return Gap; +} + +/** + Support mouse movement. Move the cursor. + + @param[in] MouseState The current mouse state. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_NOT_FOUND There was no mouse support found. +**/ +EFI_STATUS +MainEditorHandleMouseInput ( + IN EFI_SIMPLE_POINTER_STATE MouseState + ) +{ + + INT32 TextX; + INT32 TextY; + UINTN FRow; + UINTN FCol; + + LIST_ENTRY *Link; + EFI_EDITOR_LINE *Line; + + UINTN Index; + BOOLEAN Action; + + // + // mouse action means: + // mouse movement + // mouse left button + // + Action = FALSE; + + // + // have mouse movement + // + if (MouseState.RelativeMovementX || MouseState.RelativeMovementY) { + // + // handle + // + TextX = GetTextX (MouseState.RelativeMovementX); + TextY = GetTextY (MouseState.RelativeMovementY); + + FileBufferAdjustMousePosition (TextX, TextY); + + Action = TRUE; + + } + + // + // if left button pushed down + // + if (MouseState.LeftButton) { + + FCol = MainEditor.FileBuffer->MousePosition.Column - 1 + 1; + + FRow = MainEditor.FileBuffer->FilePosition.Row + + MainEditor.FileBuffer->MousePosition.Row - + MainEditor.FileBuffer->DisplayPosition.Row; + + // + // beyond the file line length + // + if (MainEditor.FileBuffer->NumLines < FRow) { + FRow = MainEditor.FileBuffer->NumLines; + } + + Link = MainEditor.FileBuffer->ListHead->ForwardLink; + for (Index = 0; Index < FRow - 1; Index++) { + Link = Link->ForwardLink; + } + + Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + + // + // beyond the line's column length + // + if (FCol > Line->Size + 1) { + FCol = Line->Size + 1; + } + + FileBufferMovePosition (FRow, FCol); + + MainEditor.FileBuffer->MousePosition.Row = MainEditor.FileBuffer->DisplayPosition.Row; + + MainEditor.FileBuffer->MousePosition.Column = MainEditor.FileBuffer->DisplayPosition.Column; + + Action = TRUE; + } + // + // mouse has action + // + if (Action) { + return EFI_SUCCESS; + } + + // + // no mouse action + // + return EFI_NOT_FOUND; +} + +/** + Handle user key input. This routes to other functions for the actions. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A load error occurred. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +MainEditorKeyInput ( + VOID + ) +{ + EFI_KEY_DATA KeyData; + EFI_STATUS Status; + EFI_SIMPLE_POINTER_STATE MouseState; + BOOLEAN NoShiftState; + + do { + + Status = EFI_SUCCESS; + EditorMouseAction = FALSE; + + // + // backup some key elements, so that can aVOID some refresh work + // + MainEditorBackup (); + + // + // change priority of checking mouse/keyboard activity dynamically + // so prevent starvation of keyboard. + // if last time, mouse moves then this time check keyboard + // + if (MainEditor.MouseSupported) { + Status = MainEditor.MouseInterface->GetState ( + MainEditor.MouseInterface, + &MouseState + ); + if (!EFI_ERROR (Status)) { + + Status = MainEditorHandleMouseInput (MouseState); + + if (!EFI_ERROR (Status)) { + EditorMouseAction = TRUE; + FileBufferMouseNeedRefresh = TRUE; + } else if (Status == EFI_LOAD_ERROR) { + StatusBarSetStatusString (L"Invalid Mouse Movement "); + } + } + } + + // + // CheckEvent() returns Success when non-partial key is pressed. + // + Status = gBS->CheckEvent (MainEditor.TextInputEx->WaitForKeyEx); + if (!EFI_ERROR (Status)) { + Status = MainEditor.TextInputEx->ReadKeyStrokeEx (MainEditor.TextInputEx, &KeyData); + if (!EFI_ERROR (Status)) { + // + // dispatch to different components' key handling function + // so not everywhere has to set this variable + // + FileBufferMouseNeedRefresh = TRUE; + // + // clear previous status string + // + StatusBarSetRefresh(); + // + // NoShiftState: TRUE when no shift key is pressed. + // + NoShiftState = ((KeyData.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) == 0) || (KeyData.KeyState.KeyShiftState == EFI_SHIFT_STATE_VALID); + // + // dispatch to different components' key handling function + // + if (EFI_NOT_FOUND != MenuBarDispatchControlHotKey(&KeyData)) { + Status = EFI_SUCCESS; + } else if (NoShiftState && ((KeyData.Key.ScanCode == SCAN_NULL) || ((KeyData.Key.ScanCode >= SCAN_UP) && (KeyData.Key.ScanCode <= SCAN_PAGE_DOWN)))) { + Status = FileBufferHandleInput (&KeyData.Key); + } else if (NoShiftState && (KeyData.Key.ScanCode >= SCAN_F1) && (KeyData.Key.ScanCode <= SCAN_F12)) { + Status = MenuBarDispatchFunctionKey (&KeyData.Key); + } else { + StatusBarSetStatusString (L"Unknown Command"); + FileBufferMouseNeedRefresh = FALSE; + } + + if (Status != EFI_SUCCESS && Status != EFI_OUT_OF_RESOURCES) { + // + // not already has some error status + // + if (StatusBarGetString() != NULL && StrCmp (L"", StatusBarGetString()) == 0) { + StatusBarSetStatusString (L"Disk Error. Try Again"); + } + } + + } + } + // + // after handling, refresh editor + // + MainEditorRefresh (); + + } while (Status != EFI_OUT_OF_RESOURCES && !EditorExit); + + return Status; +} + +/** + Set clipboard + + @param[in] Line A pointer to the line to be set to clipboard + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +MainEditorSetCutLine ( + EFI_EDITOR_LINE *Line + ) +{ + if (Line == NULL) { + return EFI_SUCCESS; + } + + if (MainEditor.CutLine != NULL) { + // + // free the old clipboard + // + LineFree (MainEditor.CutLine); + } + // + // duplicate the line to clipboard + // + MainEditor.CutLine = LineDup (Line); + if (MainEditor.CutLine == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +/** + Backup function for MainEditor + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +MainEditorBackup ( + VOID + ) +{ + FileBufferBackup (); + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.h new file mode 100644 index 00000000..8ee024c8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.h @@ -0,0 +1,66 @@ +/** @file + Declares editor interface functions. + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _LIB_EDITOR_H_ +#define _LIB_EDITOR_H_ + +#include "TextEditorTypes.h" + +/** + The initialization function for MainEditor. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +MainEditorInit ( + VOID + ); + +/** + The cleanup function for MainEditor. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +MainEditorCleanup ( + VOID + ); + +/** + Refresh the main editor component. +**/ +VOID +MainEditorRefresh ( + VOID + ); + +/** + Handle user key input. This routes to other functions for the actions. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A load error occurred. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +MainEditorKeyInput ( + VOID + ); + +/** + Backup function for MainEditor + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +MainEditorBackup ( + VOID + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.c new file mode 100644 index 00000000..e98e520c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.c @@ -0,0 +1,84 @@ +/** @file + Implementation of various string and line routines. + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "TextEditor.h" +#include "Misc.h" + +/** + Duplicate a EFI_EDITOR_LINE structure. + + @param Src The line structure to copy from. + + @retval NULL A memory allocation failed. + @return a pointer to the newly allcoated line. +**/ +EFI_EDITOR_LINE * +LineDup ( + IN EFI_EDITOR_LINE *Src + ) +{ + EFI_EDITOR_LINE *Dest; + + // + // allocate for the line structure + // + Dest = AllocateZeroPool (sizeof (EFI_EDITOR_LINE)); + if (Dest == NULL) { + return NULL; + } + // + // allocate and set the line buffer + // + Dest->Buffer = CatSPrint (NULL, L"%s", Src->Buffer); + if (Dest->Buffer == NULL) { + FreePool (Dest); + return NULL; + } + + // + // set the other structure members + // + Dest->Signature = LINE_LIST_SIGNATURE; + Dest->Size = Src->Size; + Dest->TotalSize = Dest->Size; + Dest->Type = Src->Type; + Dest->Link = Src->Link; + + return Dest; +} + +/** + Free a EFI_EDITOR_LINE structure. + + @param Src The line structure to free. +**/ +VOID +LineFree ( + IN EFI_EDITOR_LINE *Src + ) +{ + if (Src == NULL) { + return ; + } + // + // free the line buffer and then the line structure itself + // + SHELL_FREE_NON_NULL (Src->Buffer); + SHELL_FREE_NON_NULL (Src); + +} + + + + + + + + + + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.h new file mode 100644 index 00000000..ba25e4e1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.h @@ -0,0 +1,44 @@ +/** @file + Declares generic editor helper functions. + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _LIB_MISC_H_ +#define _LIB_MISC_H_ + +#include "TextEditorTypes.h" + + + +/** + Free a EFI_EDITOR_LINE structure. + + @param Src The line structure to free. +**/ +VOID +LineFree ( + IN EFI_EDITOR_LINE *Src + ); + +/** + Duplicate a EFI_EDITOR_LINE structure. + + @param Src The line structure to copy from. + + @retval NULL A memory allocation failed. + @return a pointer to the newly allcoated line. +**/ +EFI_EDITOR_LINE * +LineDup ( + IN EFI_EDITOR_LINE *Src + ); + + + + + + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditStrings.uni b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditStrings.uni new file mode 100644 index 00000000..f38221df --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditStrings.uni @@ -0,0 +1,69 @@ +// /** +// +// Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// Abstract: +// +// Additional string definitions for UEFI Shell 2.0 Debug1 profile Edit command +// +// +// **/ + +/=# + +#langdef en-US "english" + +#string STR_EDIT_LIBEDITOR_TITLEBAR #language en-US "%EMainEditor init failed on TitleBar init\r\n%N" +#string STR_EDIT_LIBEDITOR_MAINMENU #language en-US "%EMainEditor init was not successful on MainMenu init\r\n%N" +#string STR_EDIT_LIBEDITOR_STATUSBAR #language en-US "%EMainEditor init was not successful on StatusBar init\r\n%N" +#string STR_EDIT_LIBEDITOR_INPUTBAR #language en-US "%EMainEditor init was not successful on InputBar init\r\n%N" +#string STR_EDIT_LIBEDITOR_FILEBUFFER #language en-US "%EMainEditor init was not successful on FileBuffer init\r\n%N" +#string STR_EDIT_LIBEDITOR_TITLEBAR_CLEANUP #language en-US "TitleBar cleanup was not successful\r\n" +#string STR_EDIT_LIBEDITOR_MENUBAR_CLEANUP #language en-US "MenuBar cleanup was not successful\r\n" +#string STR_EDIT_LIBEDITOR_STATUSBAR_CLEANUP #language en-US "StatusBar cleanup was not successful\r\n" +#string STR_EDIT_LIBEDITOR_INPUTBAR_CLEANUP #language en-US "InputBar cleanup was not successful\r\n" +#string STR_EDIT_LIBEDITOR_FILEBUFFER_CLEANUP #language en-US "FileBuffer cleanup was not successful\r\n" +#string STR_EDIT_LIBEDITOR_MAINEDITOR_INIT #language en-US "%EMainEditor init was not succesful on TitleBar init\r\n%N" +#string STR_EDIT_LIBINPUTBAR_MAININPUTBAR #language en-US "%s" +#string STR_EDIT_LIBMENUBAR_OPEN_FILE #language en-US "Open File" +#string STR_EDIT_LIBMENUBAR_SAVE_FILE #language en-US "Save File" +#string STR_EDIT_LIBMENUBAR_EXIT #language en-US "Exit" +#string STR_EDIT_LIBMENUBAR_CUT_LINE #language en-US "Cut Line" +#string STR_EDIT_LIBMENUBAR_PASTE_LINE #language en-US "Paste Line" +#string STR_EDIT_LIBMENUBAR_GO_TO_LINE #language en-US "Go To Line" +#string STR_EDIT_LIBMENUBAR_SEARCH #language en-US "Search" +#string STR_EDIT_LIBMENUBAR_SEARCH_REPLACE #language en-US "Search/Replace" +#string STR_EDIT_LIBMENUBAR_FILE_TYPE #language en-US "File Type" +#string STR_EDIT_LIBMENUBAR_F1 #language en-US "F1" +#string STR_EDIT_LIBMENUBAR_F2 #language en-US "F2" +#string STR_EDIT_LIBMENUBAR_F3 #language en-US "F3" +#string STR_EDIT_LIBMENUBAR_F4 #language en-US "F4" +#string STR_EDIT_LIBMENUBAR_F5 #language en-US "F5" +#string STR_EDIT_LIBMENUBAR_F6 #language en-US "F6" +#string STR_EDIT_LIBMENUBAR_F7 #language en-US "F7" +#string STR_EDIT_LIBMENUBAR_F8 #language en-US "F8" +#string STR_EDIT_LIBMENUBAR_F9 #language en-US "F9" +#string STR_EDIT_LIBMENUBAR_F10 #language en-US "F10" +#string STR_EDIT_LIBMENUBAR_F11 #language en-US "F11" +#string STR_EDIT_LIBMENUBAR_F12 #language en-US "F12" +#string STR_EDIT_LIBMENUBAR_CTRL_E #language en-US "Ctrl+E" +#string STR_EDIT_LIBMENUBAR_CTRL_W #language en-US "Ctrl+W" +#string STR_EDIT_HELP_TITLE #language en-US "Help \n" +#string STR_EDIT_HELP_BLANK #language en-US " \n" +#string STR_EDIT_HELP_LIST_TITLE #language en-US "Control Key Function Key Command \n" +#string STR_EDIT_HELP_DIV #language en-US "----------- ------------ ----------------- \n" +#string STR_EDIT_HELP_GO_TO_LINE #language en-US "Ctrl-G F1 Go To Line \n" +#string STR_EDIT_HELP_SAVE_FILE #language en-US "Ctrl-S F2 Save File \n" +#string STR_EDIT_HELP_EXIT #language en-US "Ctrl-Q F3 Exit \n" +#string STR_EDIT_HELP_SEARCH #language en-US "Ctrl-F F4 Search \n" +#string STR_EDIT_HELP_SEARCH_REPLACE #language en-US "Ctrl-R F5 Search/Replace \n" +#string STR_EDIT_HELP_CUT_LINE #language en-US "Ctrl-K F6 Cut Line \n" +#string STR_EDIT_HELP_PASTE_LINE #language en-US "Ctrl-U F7 Paste Line \n" +#string STR_EDIT_HELP_OPEN_FILE #language en-US "Ctrl-O F8 Open File \n" +#string STR_EDIT_HELP_FILE_TYPE #language en-US "Ctrl-T F9 File Type \n" +#string STR_EDIT_HELP_EXIT_HELP #language en-US "Use Ctrl-W to exit this help \n" +#string STR_EDIT_MAIN_INVALID_FILE_NAME #language en-US "%Hedit%N: Invalid File Name\r\n" +#string STR_EDIT_MAIN_INIT_FAILED #language en-US "%Hedit%N: Initialization was not successful\r\n" +#string STR_EDIT_MAIN_BUFFER #language en-US "%Hedit%N: %s\r\n" +#string STR_EDIT_MAIN_UNKNOWN_EDITOR_ERR #language en-US "%Hedit%N: Unknown Editor Error\r\n" diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditor.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditor.h new file mode 100644 index 00000000..c912abb4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditor.h @@ -0,0 +1,26 @@ +/** @file + Main include file for Edit shell Debug1 function. + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_EDIT_H_ +#define _EFI_EDIT_H_ + +#include "TextEditorTypes.h" + +#include "MainTextEditor.h" +#include "FileBuffer.h" +#include "EditTitleBar.h" +#include "EditStatusBar.h" +#include "EditInputBar.h" +#include "EditMenuBar.h" +#include "Misc.h" + +extern EFI_EDITOR_GLOBAL_EDITOR MainEditor; +extern BOOLEAN EditorFirst; +extern BOOLEAN EditorExit; + +#endif // _EFI_EDIT_H_ diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditorTypes.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditorTypes.h new file mode 100644 index 00000000..49e6e218 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditorTypes.h @@ -0,0 +1,97 @@ +/** @file + Declares editor types. + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EDITOR_TYPE_H_ +#define _EDITOR_TYPE_H_ + +#include "UefiShellDebug1CommandsLib.h" +#include "EditTitleBar.h" +#include "EditMenuBar.h" + +#define MIN_POOL_SIZE 125 +#define MAX_STRING_LENGTH 127 + +typedef struct { + UINTN Row; + UINTN Column; +} EFI_EDITOR_POSITION; + +typedef +EFI_STATUS +(*EFI_MENU_ITEM_FUNCTION) ( + VOID + ); + +typedef enum { + NewLineTypeDefault, + NewLineTypeLineFeed, + NewLineTypeCarriageReturn, + NewLineTypeCarriageReturnLineFeed, + NewLineTypeLineFeedCarriageReturn, + NewLineTypeUnknown +} EE_NEWLINE_TYPE; + +#define LINE_LIST_SIGNATURE SIGNATURE_32 ('e', 'e', 'l', 'l') +typedef struct _EFI_EDITOR_LINE { + UINTN Signature; + CHAR16 *Buffer; + UINTN Size; // unit is Unicode + UINTN TotalSize; // unit is Unicode, exclude CHAR_NULL + EE_NEWLINE_TYPE Type; + LIST_ENTRY Link; +} EFI_EDITOR_LINE; + +typedef struct { + UINT32 Foreground : 4; + UINT32 Background : 4; +} EFI_EDITOR_COLOR_ATTRIBUTES; + +typedef union { + EFI_EDITOR_COLOR_ATTRIBUTES Colors; + UINTN Data; +} EFI_EDITOR_COLOR_UNION; + +typedef struct { + UINTN Columns; + UINTN Rows; +} EFI_EDITOR_TEXT_MODE; + +typedef struct { + CHAR16 *FileName; // file name current edited in editor + EDIT_FILE_TYPE FileType; // Unicode file or ASCII file + LIST_ENTRY *ListHead; // list head of lines + EFI_EDITOR_LINE *Lines; // lines of current file + UINTN NumLines; // total line numbers + EFI_EDITOR_POSITION DisplayPosition; // cursor position in screen + EFI_EDITOR_POSITION FilePosition; // cursor position in file + EFI_EDITOR_POSITION MousePosition; // mouse position in screen + // file position of first byte displayed on screen + // + EFI_EDITOR_POSITION LowVisibleRange; + + BOOLEAN FileModified; // file is modified or not + BOOLEAN ModeInsert; // input mode INS or OVR + BOOLEAN ReadOnly; // file is read-only or not + EFI_EDITOR_LINE *CurrentLine; // current line cursor is at +} EFI_EDITOR_FILE_BUFFER; + +typedef struct { + EFI_EDITOR_FILE_BUFFER *FileBuffer; + + EFI_EDITOR_COLOR_UNION ColorAttributes; + EFI_EDITOR_POSITION ScreenSize; // row number and column number + EFI_EDITOR_LINE *CutLine; // clip board + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInputEx; + BOOLEAN MouseSupported; + EFI_SIMPLE_POINTER_PROTOCOL *MouseInterface; + INT32 MouseAccumulatorX; + INT32 MouseAccumulatorY; + +} EFI_EDITOR_GLOBAL_EDITOR; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditInputBar.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditInputBar.c new file mode 100644 index 00000000..ff683e45 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditInputBar.c @@ -0,0 +1,324 @@ +/** @file + Implements inputbar interface functions. + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "EditInputBar.h" +#include "UefiShellDebug1CommandsLib.h" + +CHAR16 *mPrompt; // Input bar mPrompt string. +CHAR16 *mReturnString; // The returned string. +UINTN StringSize; // Size of mReturnString space size. +EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *mTextInEx; + +/** + Initialize the input bar. + + @param[in] TextInEx Pointer to SimpleTextInEx instance in System Table. +**/ +VOID +InputBarInit ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx + ) +{ + mPrompt = NULL; + mReturnString = NULL; + StringSize = 0; + mTextInEx = TextInEx; +} + +/** + Cleanup function for input bar. +**/ +VOID +InputBarCleanup ( + VOID + ) +{ + // + // free input bar's prompt and input string + // + SHELL_FREE_NON_NULL (mPrompt); + SHELL_FREE_NON_NULL (mReturnString); + mPrompt = NULL; + mReturnString = NULL; +} + +/** + Display the prompt. + Do the requesting of input. + + @param[in] LastColumn The last printable column. + @param[in] LastRow The last printable row. +**/ +VOID +InputBarPrintInput ( + IN UINTN LastColumn, + IN UINTN LastRow + ) +{ + UINTN Limit; + UINTN Size; + CHAR16 *Buffer; + UINTN Index; + UINTN mPromptLen; + + mPromptLen = StrLen (mPrompt); + Limit = LastColumn - mPromptLen - 1; + Size = StrLen (mReturnString); + + // + // check whether the mPrompt length and input length will + // exceed limit + // + if (Size <= Limit) { + Buffer = mReturnString; + } else { + Buffer = mReturnString + Size - Limit; + } + + gST->ConOut->EnableCursor (gST->ConOut, FALSE); + + ShellPrintEx (((INT32)mPromptLen), ((INT32)LastRow) - 1, L"%s", Buffer); + Size = StrLen (Buffer); + + // + // print " " after mPrompt + // + for (Index = Size; Index < Limit; Index++) { + ShellPrintEx ((INT32)(mPromptLen + Size), ((INT32)LastRow) - 1, L" "); + } + + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + gST->ConOut->SetCursorPosition (gST->ConOut, Size + mPromptLen, LastRow - 1); +} + +typedef struct { + UINT32 Foreground : 4; + UINT32 Background : 3; +} INPUT_BAR_COLOR_ATTRIBUTES; + +typedef union { + INPUT_BAR_COLOR_ATTRIBUTES Colors; + UINTN Data; +} INPUT_BAR_COLOR_UNION; + + +/** + The refresh function for InputBar, it will wait for user input + + @param[in] LastRow The last printable row. + @param[in] LastColumn The last printable column. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +InputBarRefresh ( + UINTN LastRow, + UINTN LastColumn + ) +{ + INPUT_BAR_COLOR_UNION Orig; + INPUT_BAR_COLOR_UNION New; + EFI_KEY_DATA KeyData; + UINTN Size; + EFI_STATUS Status; + BOOLEAN NoDisplay; + UINTN EventIndex; + UINTN CursorRow; + UINTN CursorCol; + + // + // variable initialization + // + Size = 0; + Status = EFI_SUCCESS; + + // + // back up the old screen attributes + // + CursorCol = gST->ConOut->Mode->CursorColumn; + CursorRow = gST->ConOut->Mode->CursorRow; + Orig.Data = gST->ConOut->Mode->Attribute; + New.Data = 0; + New.Colors.Foreground = Orig.Colors.Background & 0xF; + New.Colors.Background = Orig.Colors.Foreground & 0x7; + + gST->ConOut->SetAttribute (gST->ConOut, New.Data & 0x7F); + + // + // clear input bar + // + EditorClearLine (LastRow , LastColumn, LastRow); + + gST->ConOut->SetCursorPosition (gST->ConOut, 0, LastRow - 1); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBINPUTBAR_MAININPUTBAR), gShellDebug1HiiHandle, mPrompt); + + // + // this is a selection mPrompt, cursor will stay in edit area + // actually this is for search , search/replace + // + if (StrStr (mPrompt, L"Yes/No")) { + NoDisplay = TRUE; + gST->ConOut->SetCursorPosition (gST->ConOut, CursorCol, CursorRow); + gST->ConOut->SetAttribute (gST->ConOut, Orig.Data); + } else { + NoDisplay = FALSE; + } + // + // wait for user input + // + for (;;) { + Status = gBS->WaitForEvent (1, &mTextInEx->WaitForKeyEx, &EventIndex); + if (EFI_ERROR (Status) || (EventIndex != 0)) { + continue; + } + Status = mTextInEx->ReadKeyStrokeEx (mTextInEx, &KeyData); + if (EFI_ERROR (Status)) { + continue; + } + if (((KeyData.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) && + (KeyData.KeyState.KeyShiftState != EFI_SHIFT_STATE_VALID)) { + // + // Shift key pressed. + // + continue; + } + // + // pressed ESC + // + if (KeyData.Key.ScanCode == SCAN_ESC) { + Size = 0; + Status = EFI_NOT_READY; + break; + } + // + // return pressed + // + if (KeyData.Key.UnicodeChar == CHAR_LINEFEED || KeyData.Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { + break; + } else if (KeyData.Key.UnicodeChar == CHAR_BACKSPACE) { + // + // backspace + // + if (Size > 0) { + Size--; + mReturnString[Size] = CHAR_NULL; + if (!NoDisplay) { + + InputBarPrintInput (LastColumn, LastRow); + + } + } + } else if (KeyData.Key.UnicodeChar <= 127 && KeyData.Key.UnicodeChar >= 32) { + // + // VALID ASCII char pressed + // + mReturnString[Size] = KeyData.Key.UnicodeChar; + + // + // should be less than specified length + // + if (Size >= StringSize) { + continue; + } + + Size++; + + mReturnString[Size] = CHAR_NULL; + + if (!NoDisplay) { + + InputBarPrintInput (LastColumn, LastRow); + + } else { + // + // if just choose yes/no + // + break; + } + + } + } + + mReturnString[Size] = CHAR_NULL; + + + // + // restore screen attributes + // + gST->ConOut->SetCursorPosition (gST->ConOut, CursorCol, CursorRow); + gST->ConOut->SetAttribute (gST->ConOut, Orig.Data); + + return Status; +} + +/** + SetPrompt and wait for input. + + @param[in] Str The prompt string. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +InputBarSetPrompt ( + IN CONST CHAR16 *Str + ) +{ + // + // FREE the old mPrompt string + // + SHELL_FREE_NON_NULL (mPrompt); + + mPrompt = CatSPrint (NULL, L"%s ", Str); + if (mPrompt == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +/** + Set the size of the string in characters. + + @param[in] Size The max number of characters to accept. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +InputBarSetStringSize ( + UINTN Size + ) +{ + // + // free the old ReturnStirng + // + SHELL_FREE_NON_NULL (mReturnString); + + StringSize = Size; + mReturnString = AllocateZeroPool ((StringSize + 1) * sizeof(mReturnString[0])); + if (mReturnString == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +/** + Function to retrieve the input from the user. + + @retval NULL No input has been received. + @return The string that was input. +**/ +CONST CHAR16* +InputBarGetString ( + VOID + ) +{ + return (mReturnString); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditInputBar.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditInputBar.h new file mode 100644 index 00000000..c40aa59a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditInputBar.h @@ -0,0 +1,81 @@ +/** @file + Declares imputbar interface functions. + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _LIB_INPUT_BAR_H_ +#define _LIB_INPUT_BAR_H_ + +/** + Initialize the input bar. + + @param[in] TextInEx Pointer to SimpleTextInEx instance in System Table. +**/ +VOID +InputBarInit ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx + ); + +/** + Cleanup function for input bar. +**/ +VOID +InputBarCleanup ( + VOID + ); + +/** + The refresh function for InputBar, it will wait for user input + + @param[in] LastRow The last printable row. + @param[in] LastColumn The last printable column. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +InputBarRefresh ( + UINTN LastRow, + UINTN LastColumn + ); + +/** + SetPrompt and wait for input. + + @param[in] Str The prompt string. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +InputBarSetPrompt ( + IN CONST CHAR16 *Str + ); + +/** + Set the size of the string in characters. + + @param[in] Size The max number of characters to accept. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +InputBarSetStringSize ( + UINTN Size + ); + +/** + Function to retrieve the input from the user. + + @retval NULL No input has been received. + @return The string that was input. +**/ +CONST CHAR16* +InputBarGetString ( + VOID + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditMenuBar.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditMenuBar.c new file mode 100644 index 00000000..23acfb42 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditMenuBar.c @@ -0,0 +1,210 @@ +/** @file + implements menubar interface functions. + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "EditMenuBar.h" +#include "UefiShellDebug1CommandsLib.h" +#include "EditStatusBar.h" + +EDITOR_MENU_ITEM *MenuItems; +MENU_ITEM_FUNCTION *ControlBasedMenuFunctions; +UINTN NumItems; + +/** + Cleanup function for a menu bar. frees all allocated memory. +**/ +VOID +MenuBarCleanup ( + VOID + ) +{ + SHELL_FREE_NON_NULL(MenuItems); +} + +/** + Initialize the menu bar with the specified items. + + @param[in] Items The items to display and their functions. + + @retval EFI_SUCCESS The initialization was correct. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +MenuBarInit ( + IN CONST EDITOR_MENU_ITEM *Items + ) +{ + CONST EDITOR_MENU_ITEM *ItemsWalker; + + for (NumItems = 0, ItemsWalker = Items ; ItemsWalker != NULL && ItemsWalker->Function != NULL ; ItemsWalker++,NumItems++); + + MenuItems = AllocateZeroPool((NumItems+1) * sizeof(EDITOR_MENU_ITEM)); + if (MenuItems == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem(MenuItems, Items, (NumItems+1) * sizeof(EDITOR_MENU_ITEM)); + return EFI_SUCCESS; +} + +/** + Initialize the control hot-key with the specified items. + + @param[in] Items The hot-key functions. + + @retval EFI_SUCCESS The initialization was correct. +**/ +EFI_STATUS +ControlHotKeyInit ( + IN MENU_ITEM_FUNCTION *Items + ) +{ + ControlBasedMenuFunctions = Items; + return EFI_SUCCESS; +} +/** + Refresh function for the menu bar. + + @param[in] LastRow The last printable row. + @param[in] LastCol The last printable column. + + @retval EFI_SUCCESS The refresh was successful. +**/ +EFI_STATUS +MenuBarRefresh ( + IN CONST UINTN LastRow, + IN CONST UINTN LastCol + ) +{ + EDITOR_MENU_ITEM *Item; + UINTN Col; + UINTN Row; + UINTN Width; + CHAR16 *NameString; + CHAR16 *FunctionKeyString; + + // + // variable initialization + // + Col = 1; + Row = (LastRow - 2); + + // + // clear menu bar rows + // + EditorClearLine (LastRow - 2, LastCol, LastRow); + EditorClearLine (LastRow - 1, LastCol, LastRow); + EditorClearLine (LastRow , LastCol, LastRow); + + + // + // print out the menu items + // + for (Item = MenuItems; Item != NULL && Item->Function != NULL; Item++) { + + + NameString = HiiGetString(gShellDebug1HiiHandle, Item->NameToken, NULL); + + + Width = MAX ((StrLen (NameString) + 6), 20); + if (((Col + Width) > LastCol)) { + Row++; + Col = 1; + } + + FunctionKeyString = HiiGetString(gShellDebug1HiiHandle, Item->FunctionKeyToken, NULL); + + ShellPrintEx ((INT32)(Col) - 1, (INT32)(Row) - 1, L"%E%s%N %H%s%N ", FunctionKeyString, NameString); + + FreePool (NameString); + FreePool (FunctionKeyString); + Col += Width; + } + + return EFI_SUCCESS; +} + +/** + Function to dispatch the correct function based on a function key (F1...) + + @param[in] Key The pressed key. + + @retval EFI_NOT_FOUND The key was not a valid function key + (an error was sent to the status bar). + @return The return value from the called dispatch function. +**/ +EFI_STATUS +MenuBarDispatchFunctionKey ( + IN CONST EFI_INPUT_KEY *Key + ) +{ + UINTN Index; + + Index = Key->ScanCode - SCAN_F1; + + // + // check whether in range + // + if (Index > (NumItems - 1)) { + StatusBarSetStatusString (L"Unknown Command"); + return EFI_SUCCESS; + } + + return (MenuItems[Index].Function ()); +} + +/** + Function to dispatch the correct function based on a control-based key (ctrl+o...) + + @param[in] KeyData The pressed key. + + @retval EFI_NOT_FOUND The key was not a valid control-based key + (an error was sent to the status bar). + @return EFI_SUCCESS. +**/ +EFI_STATUS +MenuBarDispatchControlHotKey ( + IN CONST EFI_KEY_DATA *KeyData + ) +{ + UINT16 ControlIndex; + + // + // Set to invalid value first. + // + ControlIndex = MAX_UINT16; + + if (((KeyData->KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) == 0) || + (KeyData->KeyState.KeyShiftState == EFI_SHIFT_STATE_VALID)) { + // + // For consoles that don't support/report shift state, + // Ctrl+A is translated to 1 (UnicodeChar). + // + ControlIndex = KeyData->Key.UnicodeChar; + } else if (((KeyData->KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) && + ((KeyData->KeyState.KeyShiftState & (EFI_RIGHT_CONTROL_PRESSED | EFI_LEFT_CONTROL_PRESSED)) != 0) && + ((KeyData->KeyState.KeyShiftState & ~(EFI_SHIFT_STATE_VALID | EFI_RIGHT_CONTROL_PRESSED | EFI_LEFT_CONTROL_PRESSED)) == 0)) { + // + // For consoles that supports/reports shift state, + // make sure only CONTROL is pressed. + // + if ((KeyData->Key.UnicodeChar >= L'A') && (KeyData->Key.UnicodeChar <= L'Z')) { + ControlIndex = KeyData->Key.UnicodeChar - L'A' + 1; + } else if ((KeyData->Key.UnicodeChar >= L'a') && (KeyData->Key.UnicodeChar <= L'z')) { + ControlIndex = KeyData->Key.UnicodeChar - L'a' + 1; + } + } + if ((SCAN_CONTROL_Z < ControlIndex) + ||(NULL == ControlBasedMenuFunctions[ControlIndex])) + { + return EFI_NOT_FOUND; + } + + ControlBasedMenuFunctions[ControlIndex](); + return EFI_SUCCESS; +} + + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditMenuBar.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditMenuBar.h new file mode 100644 index 00000000..2653291d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditMenuBar.h @@ -0,0 +1,113 @@ +/** @file + Declares menubar interface functions. + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _LIB_MENU_BAR_H_ +#define _LIB_MENU_BAR_H_ + +#define SCAN_CONTROL_E 5 +#define SCAN_CONTROL_F 6 +#define SCAN_CONTROL_G 7 +#define SCAN_CONTROL_K 11 +#define SCAN_CONTROL_O 15 +#define SCAN_CONTROL_Q 17 +#define SCAN_CONTROL_R 18 +#define SCAN_CONTROL_S 19 +#define SCAN_CONTROL_T 20 +#define SCAN_CONTROL_U 21 +#define SCAN_CONTROL_W 23 +#define SCAN_CONTROL_Z 26 + + +typedef +EFI_STATUS +(*MENU_ITEM_FUNCTION) ( + VOID + ); + +typedef struct _EDITOR_MENU_ITEM { + EFI_STRING_ID NameToken; + CHAR16 FunctionKeyToken; + MENU_ITEM_FUNCTION Function; +} EDITOR_MENU_ITEM; + +/** + Initializa the menu bar with the specified items. + + @param[in] Items The items to display and their functions. + + @retval EFI_SUCCESS The initialization was correct. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +MenuBarInit ( + IN CONST EDITOR_MENU_ITEM *Items + ); + +/** + Initialize the control hot-key with the specified items. + + @param[in] Items The hot-key functions. + + @retval EFI_SUCCESS The initialization was correct. +**/ +EFI_STATUS +ControlHotKeyInit ( + IN MENU_ITEM_FUNCTION *Items + ); + +/** + Cleanup function for a menu bar. frees all allocated memory. +**/ +VOID +MenuBarCleanup ( + VOID + ); + +/** + Refresh function for the menu bar. + + @param[in] LastRow The last printable row. + @param[in] LastCol The last printable column. + + @retval EFI_SUCCESS The refresh was successful. +**/ +EFI_STATUS +MenuBarRefresh ( + IN CONST UINTN LastRow, + IN CONST UINTN LastCol + ); + +/** + Function to dispatch the correct function based on a function key (F1...) + + @param[in] Key The pressed key. + + @retval EFI_NOT_FOUND The key was not a valid function key + (an error was sent to the status bar). + @return The return value from the called dispatch function. +**/ +EFI_STATUS +MenuBarDispatchFunctionKey ( + IN CONST EFI_INPUT_KEY *Key + ); + +/** + Function to dispatch the correct function based on a control-based key (ctrl+o...) + + @param[in] KeyData The pressed key. + + @retval EFI_NOT_FOUND The key was not a valid control-based key + (an error was sent to the status bar). + @return EFI_SUCCESS. +**/ +EFI_STATUS +MenuBarDispatchControlHotKey ( + IN CONST EFI_KEY_DATA *KeyData + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditStatusBar.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditStatusBar.c new file mode 100644 index 00000000..dfa1b2c3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditStatusBar.c @@ -0,0 +1,224 @@ +/** @file + Implements statusbar interface functions. + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "EditStatusBar.h" +#include "UefiShellDebug1CommandsLib.h" + +CHAR16 *StatusString; +BOOLEAN StatusBarNeedRefresh; +BOOLEAN StatusStringChanged; + +/** + Initialization function for Status Bar. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @sa StatusBarSetStatusString +**/ +EFI_STATUS +StatusBarInit ( + VOID + ) +{ + // + // initialize the statusbar + // + StatusString = NULL; + StatusBarNeedRefresh = TRUE; + StatusStringChanged = FALSE; + + // + // status string set to "" + // + return (StatusBarSetStatusString (L"")); +} + +/** + Cleanup function for the status bar. +**/ +VOID +StatusBarCleanup ( + VOID + ) +{ + // + // free the status string and backvar's status string + // + SHELL_FREE_NON_NULL (StatusString); +} + +typedef struct { + UINT32 Foreground : 4; + UINT32 Background : 3; +} STATUS_BAR_COLOR_ATTRIBUTES; + +typedef union { + STATUS_BAR_COLOR_ATTRIBUTES Colors; + UINTN Data; +} STATUS_BAR_COLOR_UNION; + +/** + Cause the status bar to refresh it's printing on the screen. + + @param[in] EditorFirst TRUE to indicate the first launch of the editor. + FALSE otherwise. + @param[in] LastRow LastPrintable row. + @param[in] LastCol Last printable column. + @param[in] FileRow Row in the file. + @param[in] FileCol Column in the file. + @param[in] InsertMode TRUE to indicate InsertMode. FALSE otherwise. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +StatusBarRefresh ( + IN BOOLEAN EditorFirst, + IN UINTN LastRow, + IN UINTN LastCol, + IN UINTN FileRow, + IN UINTN FileCol, + IN BOOLEAN InsertMode + ) +{ + STATUS_BAR_COLOR_UNION Orig; + STATUS_BAR_COLOR_UNION New; + + if (!StatusStringChanged && StatusBarNeedRefresh) { + StatusBarSetStatusString (L"\0"); + } + // + // when it's called first time after editor launch, so refresh is mandatory + // + if (!StatusBarNeedRefresh && !StatusStringChanged) { + return EFI_SUCCESS; + } + + // + // back up the screen attributes + // + Orig.Data = gST->ConOut->Mode->Attribute; + New.Data = 0; + New.Colors.Foreground = Orig.Colors.Background & 0xF; + New.Colors.Background = Orig.Colors.Foreground & 0x7; + + gST->ConOut->EnableCursor (gST->ConOut, FALSE); + gST->ConOut->SetAttribute (gST->ConOut, New.Data & 0x7F); + + // + // clear status bar + // + EditorClearLine (LastRow, LastCol, LastRow); + + // + // print row, column fields + // + if (FileRow != (UINTN)(-1) && FileCol != (UINTN)(-1)) { + ShellPrintEx ( + 0, + (INT32)(LastRow) - 1, + L" %d,%d %s", + FileRow, + FileCol, + StatusString + ); + } else { + ShellPrintEx ( + 0, + (INT32)(LastRow) - 1, + L" %s", + StatusString + ); + } + + // + // print insert mode field + // + if (InsertMode) { + ShellPrintEx ((INT32)(LastCol) - 21, (INT32)(LastRow) - 1, L"|%s| Help: Ctrl-E", L"INS"); + } else { + ShellPrintEx ((INT32)(LastCol) - 21, (INT32)(LastRow) - 1, L"|%s| Help: Ctrl-E", L"OVR"); + } + // + // restore the old screen attributes + // + gST->ConOut->SetAttribute (gST->ConOut, Orig.Data); + + // + // restore position in edit area + // + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + + StatusBarNeedRefresh = FALSE; + StatusStringChanged = FALSE; + + return EFI_SUCCESS; +} + +/** + Set the status string text part. + + @param[in] Str The string to use. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +StatusBarSetStatusString ( + IN CHAR16 *Str + ) +{ + StatusStringChanged = TRUE; + + // + // free the old status string + // + SHELL_FREE_NON_NULL (StatusString); + StatusString = CatSPrint (NULL, L"%s", Str); + if (StatusString == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +/** + Function to retrieve the current status string. + + @return The string that is used. +**/ +CONST CHAR16* +StatusBarGetString ( + VOID + ) +{ + return (StatusString); +} + +/** + Function to set the need refresh boolean to TRUE. +**/ +VOID +StatusBarSetRefresh( + VOID + ) +{ + StatusBarNeedRefresh = TRUE; +} + +/** + Function to get the need refresh boolean to TRUE. + + @retval TRUE The status bar needs to be refreshed. +**/ +BOOLEAN +StatusBarGetRefresh( + VOID + ) +{ + return (StatusBarNeedRefresh); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditStatusBar.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditStatusBar.h new file mode 100644 index 00000000..cd77fa7c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditStatusBar.h @@ -0,0 +1,96 @@ +/** @file + Declares statusbar interface functions. + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _LIB_STATUS_BAR_H_ +#define _LIB_STATUS_BAR_H_ + +/** + Initialization function for Status Bar. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @sa StatusBarSetStatusString +**/ +EFI_STATUS +StatusBarInit ( + VOID + ); + +/** + Cleanup function for the status bar. +**/ +VOID +StatusBarCleanup ( + VOID + ); + +/** + Cause the status bar to refresh it's printing on the screen. + + @param[in] EditorFirst TRUE to indicate the first launch of the editor. + FALSE otherwise. + @param[in] LastRow LastPrintable row. + @param[in] LastCol Last printable column. + @param[in] FileRow Row in the file. + @param[in] FileCol Column in the file. + @param[in] InsertMode TRUE to indicate InsertMode. FALSE otherwise. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +StatusBarRefresh ( + IN BOOLEAN EditorFirst, + IN UINTN LastRow, + IN UINTN LastCol, + IN UINTN FileRow, + IN UINTN FileCol, + IN BOOLEAN InsertMode + ); + +/** + Set the status string text part. + + @param[in] Str The string to use. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +StatusBarSetStatusString ( + IN CHAR16 *Str + ); + +/** + Function to retrieve the current status string. + + @return The string that is used. +**/ +CONST CHAR16* +StatusBarGetString ( + VOID + ); + +/** + Function to set the need refresh boolean to TRUE. +**/ +VOID +StatusBarSetRefresh( + VOID + ); + +/** + Function to get the need refresh boolean to TRUE. + + @retval TRUE The status bar needs to be refreshed. +**/ +BOOLEAN +StatusBarGetRefresh( + VOID + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditTitleBar.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditTitleBar.c new file mode 100644 index 00000000..97ef2e88 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditTitleBar.c @@ -0,0 +1,201 @@ +/** @file + Implements titlebar interface functions. + + (C) Copyright 2013 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2005 - 2014, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "EditTitleBar.h" +#include "UefiShellDebug1CommandsLib.h" + +CHAR16 *Title = NULL; + +/** + Initialize a title bar. + + @param[in] Prompt The prompt to print in the title bar. + + @retval EFI_SUCCESS The initialization was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +MainTitleBarInit ( + CONST CHAR16 *Prompt + ) +{ + SHELL_FREE_NON_NULL (Title); + if (Prompt == NULL) { + Title = CatSPrint (NULL, L""); + } else { + // + // set Title + // + Title = CatSPrint (NULL, L"%s", Prompt); + } + if (Title == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +/** + Clean up the memory used. +**/ +VOID +MainTitleBarCleanup ( + VOID + ) +{ + SHELL_FREE_NON_NULL (Title); + Title = NULL; +} + +typedef struct { + UINT32 Foreground : 4; + UINT32 Background : 4; +} TITLE_BAR_COLOR_ATTRIBUTES; + +typedef union { + TITLE_BAR_COLOR_ATTRIBUTES Colors; + UINTN Data; +} TITLE_BAR_COLOR_UNION; + +/** + Refresh function for MainTitleBar + + @param[in] FileName The open file's name (or NULL). + @param[in] FileType The type fo the file. + @param[in] ReadOnly TRUE if the file is read only. FALSE otherwise. + @param[in] Modified TRUE if the file was modified. FALSE otherwise. + @param[in] LastCol The last printable column. + @param[in] LastRow The last printable row. + @param[in] Offset The offset into the file. (only for mem/disk) + @param[in] Size The file's size. (only for mem/disk) + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +MainTitleBarRefresh ( + IN CONST CHAR16 *FileName OPTIONAL, + IN CONST EDIT_FILE_TYPE FileType, + IN CONST BOOLEAN ReadOnly, + IN CONST BOOLEAN Modified, + IN CONST UINTN LastCol, + IN CONST UINTN LastRow, + IN CONST UINTN Offset, + IN CONST UINTN Size + ) +{ + TITLE_BAR_COLOR_UNION Orig; + TITLE_BAR_COLOR_UNION New; + CONST CHAR16 *FileNameTmp; + INTN TempInteger; + + + // + // backup the old screen attributes + // + Orig.Data = gST->ConOut->Mode->Attribute; + New.Data = 0; + New.Colors.Foreground = Orig.Colors.Background & 0xF; + New.Colors.Background = Orig.Colors.Foreground & 0x7; + + gST->ConOut->SetAttribute (gST->ConOut, New.Data & 0x7F); + + // + // clear the title line + // + EditorClearLine (1, LastCol, LastRow); + + if (Title != NULL) { + // + // print the new title bar prefix + // + ShellPrintEx ( + 0, + 0, + L"%s ", + Title + ); + } + if (FileName == NULL) { + gST->ConOut->SetAttribute (gST->ConOut, Orig.Data); + return EFI_SUCCESS; + } + // + // First Extract the FileName from fullpath + // + FileNameTmp = FileName; + for (TempInteger = StrLen (FileNameTmp) - 1; TempInteger >= 0; TempInteger--) { + if (FileNameTmp[TempInteger] == L'\\') { + break; + } + } + + FileNameTmp = FileNameTmp + TempInteger + 1; + + // + // the space for file name is 20 characters + // + if (StrLen (FileNameTmp) <= 20) { + ShellPrintEx (-1,-1, L"%s ", FileNameTmp); + for (TempInteger = StrLen (FileNameTmp); TempInteger < 20; TempInteger++) { + ShellPrintEx (-1,-1, L" "); + } + + } else { + for (TempInteger = 0; TempInteger < 17; TempInteger++) { + ShellPrintEx (-1,-1, L"%c", FileNameTmp[TempInteger]); + } + // + // print "..." + // + ShellPrintEx (-1,-1, L"... "); + } + // + // print file type field + // + switch (FileType){ + case FileTypeAscii: + case FileTypeUnicode: + if (FileType == FileTypeAscii){ + ShellPrintEx (-1,-1, L" ASCII "); + } else { + ShellPrintEx (-1,-1, L" UNICODE "); + } + // + // print read-only field for text files + // + if (ReadOnly) { + ShellPrintEx (-1,-1, L"ReadOnly "); + } else { + ShellPrintEx (-1,-1, L" "); + } + break; + case FileTypeDiskBuffer: + case FileTypeMemBuffer: + // + // Print the offset. + // + ShellPrintEx (-1,-1, L"Offset %X | Size %X", Offset, Size); + case FileTypeFileBuffer: + break; + default: + break; + } + // + // print modified field + // + if (Modified) { + ShellPrintEx (-1,-1, L"Modified"); + } + // + // restore the old attribute + // + gST->ConOut->SetAttribute (gST->ConOut, Orig.Data); + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditTitleBar.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditTitleBar.h new file mode 100644 index 00000000..406d0286 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EditTitleBar.h @@ -0,0 +1,68 @@ +/** @file + Declares titlebar interface functions. + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _LIB_TITLE_BAR_H_ +#define _LIB_TITLE_BAR_H_ + +/** + Initialize a title bar. + + @param[in] Prompt The prompt to print in the title bar. + + @retval EFI_SUCCESS The initialization was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +MainTitleBarInit ( + CONST CHAR16 *Prompt + ); + +/** + Clean up the memory used. +**/ +VOID +MainTitleBarCleanup ( + VOID + ); + +typedef enum { + FileTypeNone, + FileTypeAscii, + FileTypeUnicode, + FileTypeDiskBuffer, + FileTypeMemBuffer, + FileTypeFileBuffer +} EDIT_FILE_TYPE; + +/** + Refresh function for MainTitleBar + + @param[in] FileName The open file's name (or NULL). + @param[in] FileType The type fo the file. + @param[in] ReadOnly TRUE if the file is read only. FALSE otherwise. + @param[in] Modified TRUE if the file was modified. FALSE otherwise. + @param[in] LastCol The last printable column. + @param[in] LastRow The last printable row. + @param[in] Offset The offset into the file. (only for mem/disk) + @param[in] Size The file's size. (only for mem/disk) + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +MainTitleBarRefresh ( + IN CONST CHAR16 *FileName OPTIONAL, + IN CONST EDIT_FILE_TYPE FileType, + IN CONST BOOLEAN ReadOnly, + IN CONST BOOLEAN Modified, + IN CONST UINTN LastCol, + IN CONST UINTN LastRow, + IN CONST UINTN Offset, + IN CONST UINTN Size + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EfiCompress.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EfiCompress.c new file mode 100644 index 00000000..ceb30c91 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EfiCompress.c @@ -0,0 +1,158 @@ +/** @file + Main file for EfiCompress shell Debug1 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDebug1CommandsLib.h" +#include "Compress.h" + +/** + Function for 'compress' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunEfiCompress ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + SHELL_FILE_HANDLE InShellFileHandle; + SHELL_FILE_HANDLE OutShellFileHandle; + UINT64 OutSize; + UINTN OutSize2; + VOID *OutBuffer; + UINT64 InSize; + UINTN InSize2; + VOID *InBuffer; + CHAR16 *InFileName; + CONST CHAR16 *OutFileName; + CONST CHAR16 *TempParam; + + InFileName = NULL; + OutFileName = NULL; + OutSize = 0; + ShellStatus = SHELL_SUCCESS; + Status = EFI_SUCCESS; + OutBuffer = NULL; + InShellFileHandle = NULL; + OutShellFileHandle = NULL; + InBuffer = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"eficompress", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetCount(Package) > 3) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"eficompress"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetCount(Package) < 3) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"eficompress"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + TempParam = ShellCommandLineGetRawValue(Package, 1); + ASSERT(TempParam != NULL); + InFileName = ShellFindFilePath(TempParam); + OutFileName = ShellCommandLineGetRawValue(Package, 2); + if (InFileName == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_FILE_FIND_FAIL), gShellDebug1HiiHandle, L"eficompress", TempParam); + ShellStatus = SHELL_NOT_FOUND; + } else { + if (ShellIsDirectory(InFileName) == EFI_SUCCESS){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_FILE_NOT_DIR), gShellDebug1HiiHandle, L"eficompress", InFileName); + ShellStatus = SHELL_INVALID_PARAMETER; + } + if (ShellIsDirectory(OutFileName) == EFI_SUCCESS){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_FILE_NOT_DIR), gShellDebug1HiiHandle, L"eficompress", OutFileName); + ShellStatus = SHELL_INVALID_PARAMETER; + } + if (ShellStatus == SHELL_SUCCESS) { + Status = ShellOpenFileByName(InFileName, &InShellFileHandle, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"eficompress", ShellCommandLineGetRawValue(Package, 1)); + ShellStatus = SHELL_NOT_FOUND; + } + Status = ShellOpenFileByName(OutFileName, &OutShellFileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"eficompress", ShellCommandLineGetRawValue(Package, 2)); + ShellStatus = SHELL_NOT_FOUND; + } + } + if (ShellStatus == SHELL_SUCCESS) { + Status = gEfiShellProtocol->GetFileSize(InShellFileHandle, &InSize); + ASSERT_EFI_ERROR(Status); + InBuffer = AllocateZeroPool((UINTN)InSize); + if (InBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + InSize2 = (UINTN) InSize; + Status = gEfiShellProtocol->ReadFile (InShellFileHandle, &InSize2, InBuffer); + InSize = InSize2; + ASSERT_EFI_ERROR (Status); + Status = Compress (InBuffer, InSize, OutBuffer, &OutSize); + if (Status == EFI_BUFFER_TOO_SMALL) { + OutBuffer = AllocateZeroPool ((UINTN) OutSize); + if (OutBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + Status = Compress (InBuffer, InSize, OutBuffer, &OutSize); + } + } + } + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_EFI_COMPRESS_FAIL), gShellDebug1HiiHandle, Status); + ShellStatus = ((Status == EFI_OUT_OF_RESOURCES) ? SHELL_OUT_OF_RESOURCES : SHELL_DEVICE_ERROR); + } else { + OutSize2 = (UINTN)OutSize; + Status = gEfiShellProtocol->WriteFile(OutShellFileHandle, &OutSize2, OutBuffer); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_FILE_WRITE_FAIL), gShellDebug1HiiHandle, L"eficompress", OutFileName); + ShellStatus = SHELL_DEVICE_ERROR; + } + } + } + } + } + + ShellCommandLineFreeVarList (Package); + } + if (InShellFileHandle != NULL) { + gEfiShellProtocol->CloseFile(InShellFileHandle); + } + if (OutShellFileHandle != NULL) { + gEfiShellProtocol->CloseFile(OutShellFileHandle); + } + SHELL_FREE_NON_NULL(InFileName); + SHELL_FREE_NON_NULL(InBuffer); + SHELL_FREE_NON_NULL(OutBuffer); + + return (ShellStatus); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EfiDecompress.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EfiDecompress.c new file mode 100644 index 00000000..307cdd4c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/EfiDecompress.c @@ -0,0 +1,180 @@ +/** @file + Main file for EfiDecompress shell Debug1 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDebug1CommandsLib.h" +#include + + +/** + Function for 'decompress' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunEfiDecompress ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + SHELL_FILE_HANDLE InFileHandle; + SHELL_FILE_HANDLE OutFileHandle; + UINT32 OutSize; + UINTN OutSizeTemp; + VOID *OutBuffer; + UINTN InSize; + VOID *InBuffer; + CHAR16 *InFileName; + CONST CHAR16 *OutFileName; + UINT64 Temp64Bit; + UINT32 ScratchSize; + VOID *ScratchBuffer; + EFI_DECOMPRESS_PROTOCOL *Decompress; + CONST CHAR16 *TempParam; + + InFileName = NULL; + OutFileName = NULL; + OutSize = 0; + ScratchSize = 0; + ShellStatus = SHELL_SUCCESS; + Status = EFI_SUCCESS; + OutBuffer = NULL; + InBuffer = NULL; + ScratchBuffer = NULL; + InFileHandle = NULL; + OutFileHandle = NULL; + Decompress = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"efidecompress", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetCount(Package) > 3) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"efidecompress"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetCount(Package) < 3) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"efidecompress"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + TempParam = ShellCommandLineGetRawValue(Package, 1); + ASSERT(TempParam != NULL); + InFileName = ShellFindFilePath(TempParam); + OutFileName = ShellCommandLineGetRawValue(Package, 2); + if (InFileName == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_FILE_FIND_FAIL), gShellDebug1HiiHandle, L"efidecompress", TempParam); + ShellStatus = SHELL_NOT_FOUND; + } else { + if (ShellIsDirectory(InFileName) == EFI_SUCCESS){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_FILE_NOT_DIR), gShellDebug1HiiHandle, L"efidecompress", InFileName); + ShellStatus = SHELL_INVALID_PARAMETER; + } + if (ShellIsDirectory(OutFileName) == EFI_SUCCESS){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_FILE_NOT_DIR), gShellDebug1HiiHandle, L"efidecompress", OutFileName); + ShellStatus = SHELL_INVALID_PARAMETER; + } + if (ShellStatus == SHELL_SUCCESS) { + Status = ShellOpenFileByName(InFileName, &InFileHandle, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"efidecompress", ShellCommandLineGetRawValue(Package, 1)); + ShellStatus = SHELL_NOT_FOUND; + } + } + + if (ShellStatus == SHELL_SUCCESS) { + Status = FileHandleGetSize(InFileHandle, &Temp64Bit); + ASSERT(Temp64Bit <= (UINT32)(-1)); + InSize = (UINTN)Temp64Bit; + ASSERT_EFI_ERROR(Status); + InBuffer = AllocateZeroPool(InSize); + if (InBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + Status = gEfiShellProtocol->ReadFile (InFileHandle, &InSize, InBuffer); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID**) &Decompress); + ASSERT_EFI_ERROR (Status); + + Status = Decompress->GetInfo (Decompress, InBuffer, (UINT32) InSize, &OutSize, &ScratchSize); + } + + if (EFI_ERROR(Status) || OutSize == 0) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_EFI_DECOMPRESS_NOPE), gShellDebug1HiiHandle, InFileName); + ShellStatus = SHELL_NOT_FOUND; + } else { + Status = ShellOpenFileByName(OutFileName, &OutFileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_FILE_OPEN_FAIL), gShellDebug1HiiHandle, ShellCommandLineGetRawValue(Package, 2), Status); + ShellStatus = SHELL_NOT_FOUND; + } else { + OutBuffer = AllocateZeroPool(OutSize); + ScratchBuffer = AllocateZeroPool(ScratchSize); + if (OutBuffer == NULL || ScratchBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + Status = Decompress->Decompress (Decompress, InBuffer, (UINT32) InSize, OutBuffer, OutSize, ScratchBuffer, ScratchSize); + } + } + } + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_EFI_DECOMPRESS_FAIL), gShellDebug1HiiHandle, Status); + ShellStatus = ((Status == EFI_OUT_OF_RESOURCES) ? SHELL_OUT_OF_RESOURCES : SHELL_DEVICE_ERROR); + } else { + OutSizeTemp = OutSize; + Status = gEfiShellProtocol->WriteFile (OutFileHandle, &OutSizeTemp, OutBuffer); + OutSize = (UINT32) OutSizeTemp; + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_FILE_WRITE_FAIL), gShellDebug1HiiHandle, L"efidecompress", OutFileName, Status); + ShellStatus = SHELL_DEVICE_ERROR; + } + } + } + } + } + + ShellCommandLineFreeVarList (Package); + } + if (InFileHandle != NULL) { + gEfiShellProtocol->CloseFile(InFileHandle); + } + if (OutFileHandle != NULL) { + gEfiShellProtocol->CloseFile(OutFileHandle); + } + + SHELL_FREE_NON_NULL(InFileName); + SHELL_FREE_NON_NULL(InBuffer); + SHELL_FREE_NON_NULL(OutBuffer); + SHELL_FREE_NON_NULL(ScratchBuffer); + + return (ShellStatus); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/BufferImage.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/BufferImage.c new file mode 100644 index 00000000..70103cc6 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/BufferImage.c @@ -0,0 +1,2469 @@ +/** @file + Defines HBufferImage - the view of the file that is visible at any point, + as well as the event handlers for editing the file + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "HexEditor.h" + +extern EFI_HANDLE HImageHandleBackup; + +extern HEFI_EDITOR_FILE_IMAGE HFileImage; +extern HEFI_EDITOR_DISK_IMAGE HDiskImage; +extern HEFI_EDITOR_MEM_IMAGE HMemImage; + +extern HEFI_EDITOR_FILE_IMAGE HFileImageBackupVar; +extern HEFI_EDITOR_DISK_IMAGE HDiskImageBackupVar; +extern HEFI_EDITOR_MEM_IMAGE HMemImageBackupVar; + +extern BOOLEAN HEditorMouseAction; + +extern HEFI_EDITOR_GLOBAL_EDITOR HMainEditor; +extern HEFI_EDITOR_GLOBAL_EDITOR HMainEditorBackupVar; + +HEFI_EDITOR_BUFFER_IMAGE HBufferImage; +HEFI_EDITOR_BUFFER_IMAGE HBufferImageBackupVar; + +// +// for basic initialization of HBufferImage +// +HEFI_EDITOR_BUFFER_IMAGE HBufferImageConst = { + NULL, + NULL, + 0, + NULL, + { + 0, + 0 + }, + { + 0, + 0 + }, + { + 0, + 0 + }, + 0, + TRUE, + FALSE, + FileTypeNone, + NULL, + NULL, + NULL +}; + +// +// the whole edit area needs to be refreshed +// +BOOLEAN HBufferImageNeedRefresh; + +// +// only the current line in edit area needs to be refresh +// +BOOLEAN HBufferImageOnlyLineNeedRefresh; + +BOOLEAN HBufferImageMouseNeedRefresh; + +/** + Initialization function for HBufferImage + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HBufferImageInit ( + VOID + ) +{ + EFI_STATUS Status; + + // + // basically initialize the HBufferImage + // + CopyMem (&HBufferImage, &HBufferImageConst, sizeof (HBufferImage)); + + // + // INIT listhead + // + HBufferImage.ListHead = AllocateZeroPool (sizeof (LIST_ENTRY)); + if (HBufferImage.ListHead == NULL) { + return EFI_LOAD_ERROR; + } + + InitializeListHead (HBufferImage.ListHead); + + HBufferImage.DisplayPosition.Row = 2; + HBufferImage.DisplayPosition.Column = 10; + HBufferImage.MousePosition.Row = 2; + HBufferImage.MousePosition.Column = 10; + + HBufferImage.FileImage = &HFileImage; + HBufferImage.DiskImage = &HDiskImage; + HBufferImage.MemImage = &HMemImage; + + HBufferImageNeedRefresh = FALSE; + HBufferImageOnlyLineNeedRefresh = FALSE; + HBufferImageMouseNeedRefresh = FALSE; + + HBufferImageBackupVar.FileImage = &HFileImageBackupVar; + HBufferImageBackupVar.DiskImage = &HDiskImageBackupVar; + HBufferImageBackupVar.MemImage = &HMemImageBackupVar; + + Status = HFileImageInit (); + if (EFI_ERROR (Status)) { + return EFI_LOAD_ERROR; + } + + Status = HDiskImageInit (); + if (EFI_ERROR (Status)) { + return EFI_LOAD_ERROR; + } + + Status = HMemImageInit (); + if (EFI_ERROR (Status)) { + return EFI_LOAD_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Backup function for HBufferImage. Only a few fields need to be backup. + This is for making the file buffer refresh as few as possible. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HBufferImageBackup ( + VOID + ) +{ + HBufferImageBackupVar.MousePosition = HBufferImage.MousePosition; + + HBufferImageBackupVar.BufferPosition = HBufferImage.BufferPosition; + + HBufferImageBackupVar.Modified = HBufferImage.Modified; + + HBufferImageBackupVar.BufferType = HBufferImage.BufferType; + HBufferImageBackupVar.LowVisibleRow = HBufferImage.LowVisibleRow; + HBufferImageBackupVar.HighBits = HBufferImage.HighBits; + + // + // three kinds of buffer supported + // file buffer + // disk buffer + // memory buffer + // + switch (HBufferImage.BufferType) { + case FileTypeFileBuffer: + HFileImageBackup (); + break; + + case FileTypeDiskBuffer: + HDiskImageBackup (); + break; + + case FileTypeMemBuffer: + HMemImageBackup (); + break; + + default: + break; + } + + return EFI_SUCCESS; +} + +/** + Free all the lines in HBufferImage. + Fields affected: + Lines + CurrentLine + NumLines + ListHead + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HBufferImageFreeLines ( + VOID + ) +{ + HFreeLines (HBufferImage.ListHead, HBufferImage.Lines); + + HBufferImage.Lines = NULL; + HBufferImage.CurrentLine = NULL; + HBufferImage.NumLines = 0; + + return EFI_SUCCESS; +} + +/** + Cleanup function for HBufferImage + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HBufferImageCleanup ( + VOID + ) +{ + EFI_STATUS Status; + + // + // free all the lines + // + Status = HBufferImageFreeLines (); + + SHELL_FREE_NON_NULL (HBufferImage.ListHead); + HBufferImage.ListHead = NULL; + + HFileImageCleanup (); + HDiskImageCleanup (); + + return Status; + +} + +/** + Print Line on Row + + @param[in] Line The lline to print. + @param[in] Row The row on screen ( begin from 1 ). + @param[in] FRow The FRow. + @param[in] Orig The original color. + @param[in] New The color to print with. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HBufferImagePrintLine ( + IN HEFI_EDITOR_LINE *Line, + IN UINTN Row, + IN UINTN FRow, + IN HEFI_EDITOR_COLOR_UNION Orig, + IN HEFI_EDITOR_COLOR_UNION New + + ) +{ + + UINTN Index; + UINTN Pos; + BOOLEAN Selected; + BOOLEAN BeNewColor; + UINTN RowStart; + UINTN RowEnd; + UINTN ColStart; + UINTN ColEnd; + + // + // variable initialization + // + ColStart = 0; + ColEnd = 0; + Selected = FALSE; + + // + // print the selected area in opposite color + // + if (HMainEditor.SelectStart != 0 && HMainEditor.SelectEnd != 0) { + RowStart = (HMainEditor.SelectStart - 1) / 0x10 + 1; + RowEnd = (HMainEditor.SelectEnd - 1) / 0x10 + 1; + + ColStart = (HMainEditor.SelectStart - 1) % 0x10 + 1; + ColEnd = (HMainEditor.SelectEnd - 1) % 0x10 + 1; + + if (FRow >= RowStart && FRow <= RowEnd) { + Selected = TRUE; + } + + if (FRow > RowStart) { + ColStart = 1; + } + + if (FRow < RowEnd) { + ColEnd = 0x10; + } + + } + + if (!HEditorMouseAction) { + ShellPrintEx ( + 0, + (INT32)Row - 1, + L"%8X ", + ((INT32)Row - 2 + HBufferImage.LowVisibleRow - 1) * 0x10 + ); + + } + + for (Index = 0; Index < 0x08 && Index < Line->Size; Index++) { + + BeNewColor = FALSE; + + if (Selected) { + if (Index + 1 >= ColStart && Index + 1 <= ColEnd) { + BeNewColor = TRUE; + } + } + + if (BeNewColor) { + gST->ConOut->SetAttribute (gST->ConOut, New.Data & 0x7F); + } else { + gST->ConOut->SetAttribute (gST->ConOut, Orig.Data & 0x7F); + } + + Pos = 10 + (Index * 3); + if (Line->Buffer[Index] < 0x10) { + ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"0"); + Pos++; + } + + if (Index < 0x07) { + ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"%x ", Line->Buffer[Index]); + } else { + ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"%x ", Line->Buffer[Index]); + } + + } + + gST->ConOut->SetAttribute (gST->ConOut, Orig.Data & 0x7F); + while (Index < 0x08) { + Pos = 10 + (Index * 3); + ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L" "); + Index++; + } + + while (Index < 0x10 && Index < Line->Size) { + + BeNewColor = FALSE; + + if (Selected) { + if (Index + 1 >= ColStart && Index + 1 <= ColEnd) { + BeNewColor = TRUE; + } + } + + if (BeNewColor) { + gST->ConOut->SetAttribute (gST->ConOut, New.Data & 0x7F); + } else { + gST->ConOut->SetAttribute (gST->ConOut, Orig.Data & 0x7F); + } + + Pos = 10 + (Index * 3) + 1; + if (Line->Buffer[Index] < 0x10) { + ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"0"); + Pos++; + } + + ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"%x ", Line->Buffer[Index]); + Index++; + } + + gST->ConOut->SetAttribute (gST->ConOut, Orig.Data & 0x7F); + while (Index < 0x10) { + Pos = 10 + (Index * 3) + 1; + ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L" "); + Index++; + } + // + // restore the original color + // + gST->ConOut->SetAttribute (gST->ConOut, Orig.Data & 0x7F); + + // + // PRINT the buffer content + // + if (!HEditorMouseAction) { + for (Index = 0; Index < 0x10 && Index < Line->Size; Index++) { + Pos = ASCII_POSITION + Index; + + // + // learned from shelle.h -- IsValidChar + // + if (Line->Buffer[Index] >= L' ') { + ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"%c", (CHAR16) Line->Buffer[Index]); + } else { + ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"%c", '.'); + } + } + + while (Index < 0x10) { + Pos = ASCII_POSITION + Index; + ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L" "); + Index++; + } + } + // + // restore the abundant blank in hex edit area to original color + // + if (Selected) { + if (ColEnd <= 7) { + Pos = 10 + (ColEnd - 1) * 3 + 2; + ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L" "); + } else if (ColEnd == 8) { + Pos = 10 + (ColEnd - 1) * 3 + 2; + ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L" "); + } else { + Pos = 10 + (ColEnd - 1) * 3 + 3; + ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L" "); + } + } + + return EFI_SUCCESS; +} + +/** + Function to decide if a column number is stored in the high bits. + + @param[in] Column The column to examine. + @param[out] FCol The actual column number. + + @retval TRUE The actual column was in high bits and is now in FCol. + @retval FALSE There was not a column number in the high bits. +**/ +BOOLEAN +HBufferImageIsAtHighBits ( + IN UINTN Column, + OUT UINTN *FCol + ) +{ + Column -= 10; + + // + // NOW AFTER THE SUB, Column start from 0 + // 23 AND 24 ARE BOTH BLANK + // + if (Column == 24) { + *FCol = 0; + return FALSE; + } + + if (Column > 24) { + Column--; + } + + *FCol = (Column / 3) + 1; + + if (Column % 3 == 0) { + return TRUE; + } + + if ((Column % 3 == 2)) { + *FCol = 0; + } + + return FALSE; +} + +/** + Decide if a point is in the already selected area. + + @param[in] MouseRow The row of the point to test. + @param[in] MouseCol The col of the point to test. + + @retval TRUE The point is in the selected area. + @retval FALSE The point is not in the selected area. +**/ +BOOLEAN +HBufferImageIsInSelectedArea ( + IN UINTN MouseRow, + IN UINTN MouseCol + ) +{ + UINTN FRow; + UINTN RowStart; + UINTN RowEnd; + UINTN ColStart; + UINTN ColEnd; + UINTN MouseColStart; + UINTN MouseColEnd; + + // + // judge mouse position whether is in selected area + // + // + // not select + // + if (HMainEditor.SelectStart == 0 || HMainEditor.SelectEnd == 0) { + return FALSE; + } + // + // calculate the select area + // + RowStart = (HMainEditor.SelectStart - 1) / 0x10 + 1; + RowEnd = (HMainEditor.SelectEnd - 1) / 0x10 + 1; + + ColStart = (HMainEditor.SelectStart - 1) % 0x10 + 1; + ColEnd = (HMainEditor.SelectEnd - 1) % 0x10 + 1; + + FRow = HBufferImage.LowVisibleRow + MouseRow - 2; + if (FRow < RowStart || FRow > RowEnd) { + return FALSE; + } + + if (FRow > RowStart) { + ColStart = 1; + } + + if (FRow < RowEnd) { + ColEnd = 0x10; + } + + MouseColStart = 10 + (ColStart - 1) * 3; + if (ColStart > 8) { + MouseColStart++; + } + + MouseColEnd = 10 + (ColEnd - 1) * 3 + 1; + if (ColEnd > 8) { + MouseColEnd++; + } + + if (MouseCol < MouseColStart || MouseCol > MouseColEnd) { + return FALSE; + } + + return TRUE; +} + +/** + Set mouse position according to HBufferImage.MousePosition. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HBufferImageRestoreMousePosition ( + VOID + ) +{ + HEFI_EDITOR_COLOR_UNION Orig; + HEFI_EDITOR_COLOR_UNION New; + UINTN FRow; + UINTN FColumn; + BOOLEAN HasCharacter; + HEFI_EDITOR_LINE *CurrentLine; + HEFI_EDITOR_LINE *Line; + UINT8 Value; + BOOLEAN HighBits; + + Line = NULL; + if (HMainEditor.MouseSupported) { + + if (HBufferImageMouseNeedRefresh) { + + HBufferImageMouseNeedRefresh = FALSE; + + // + // if mouse position not moved and only mouse action + // so do not need to refresh mouse position + // + if (( + HBufferImage.MousePosition.Row == HBufferImageBackupVar.MousePosition.Row && + HBufferImage.MousePosition.Column == HBufferImageBackupVar.MousePosition.Column + ) && + HEditorMouseAction + ) { + return EFI_SUCCESS; + } + // + // backup the old screen attributes + // + Orig = HMainEditor.ColorAttributes; + New.Data = 0; + New.Colors.Foreground = Orig.Colors.Background & 0xF; + New.Colors.Background = Orig.Colors.Foreground & 0x7; + + // + // if in selected area, + // so do not need to refresh mouse + // + if (!HBufferImageIsInSelectedArea ( + HBufferImageBackupVar.MousePosition.Row, + HBufferImageBackupVar.MousePosition.Column + )) { + gST->ConOut->SetAttribute (gST->ConOut, Orig.Data); + } else { + gST->ConOut->SetAttribute (gST->ConOut, New.Data & 0x7F); + } + // + // clear the old mouse position + // + FRow = HBufferImage.LowVisibleRow + HBufferImageBackupVar.MousePosition.Row - 2; + + HighBits = HBufferImageIsAtHighBits ( + HBufferImageBackupVar.MousePosition.Column, + &FColumn + ); + + HasCharacter = TRUE; + if (FRow > HBufferImage.NumLines || FColumn == 0) { + HasCharacter = FALSE; + } else { + CurrentLine = HBufferImage.CurrentLine; + Line = HMoveLine (FRow - HBufferImage.BufferPosition.Row); + + if (Line == NULL || FColumn > Line->Size) { + HasCharacter = FALSE; + } + + HBufferImage.CurrentLine = CurrentLine; + } + + ShellPrintEx ( + (INT32)HBufferImageBackupVar.MousePosition.Column - 1, + (INT32)HBufferImageBackupVar.MousePosition.Row - 1, + L" " + ); + + if (HasCharacter) { + if (HighBits) { + Value = (UINT8) (Line->Buffer[FColumn - 1] & 0xf0); + Value = (UINT8) (Value >> 4); + } else { + Value = (UINT8) (Line->Buffer[FColumn - 1] & 0xf); + } + + ShellPrintEx ( + (INT32)HBufferImageBackupVar.MousePosition.Column - 1, + (INT32)HBufferImageBackupVar.MousePosition.Row - 1, + L"%x", + Value + ); + } + + if (!HBufferImageIsInSelectedArea ( + HBufferImage.MousePosition.Row, + HBufferImage.MousePosition.Column + )) { + gST->ConOut->SetAttribute (gST->ConOut, New.Data & 0x7F); + } else { + gST->ConOut->SetAttribute (gST->ConOut, Orig.Data); + } + // + // clear the old mouse position + // + FRow = HBufferImage.LowVisibleRow + HBufferImage.MousePosition.Row - 2; + + HighBits = HBufferImageIsAtHighBits ( + HBufferImage.MousePosition.Column, + &FColumn + ); + + HasCharacter = TRUE; + if (FRow > HBufferImage.NumLines || FColumn == 0) { + HasCharacter = FALSE; + } else { + CurrentLine = HBufferImage.CurrentLine; + Line = HMoveLine (FRow - HBufferImage.BufferPosition.Row); + + if (Line == NULL || FColumn > Line->Size) { + HasCharacter = FALSE; + } + + HBufferImage.CurrentLine = CurrentLine; + } + + ShellPrintEx ( + (INT32)HBufferImage.MousePosition.Column - 1, + (INT32)HBufferImage.MousePosition.Row - 1, + L" " + ); + + if (HasCharacter) { + if (HighBits) { + Value = (UINT8) (Line->Buffer[FColumn - 1] & 0xf0); + Value = (UINT8) (Value >> 4); + } else { + Value = (UINT8) (Line->Buffer[FColumn - 1] & 0xf); + } + + ShellPrintEx ( + (INT32)HBufferImage.MousePosition.Column - 1, + (INT32)HBufferImage.MousePosition.Row - 1, + L"%x", + Value + ); + } + // + // end of HasCharacter + // + gST->ConOut->SetAttribute (gST->ConOut, Orig.Data); + } + // + // end of MouseNeedRefresh + // + } + // + // end of MouseSupported + // + return EFI_SUCCESS; +} + +/** + Set cursor position according to HBufferImage.DisplayPosition. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HBufferImageRestorePosition ( + VOID + ) +{ + // + // set cursor position + // + gST->ConOut->SetCursorPosition ( + gST->ConOut, + HBufferImage.DisplayPosition.Column - 1, + HBufferImage.DisplayPosition.Row - 1 + ); + + return EFI_SUCCESS; +} + +/** + Refresh function for HBufferImage. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A Load error occurred. + +**/ +EFI_STATUS +HBufferImageRefresh ( + VOID + ) +{ + LIST_ENTRY *Link; + HEFI_EDITOR_LINE *Line; + UINTN Row; + HEFI_EDITOR_COLOR_UNION Orig; + HEFI_EDITOR_COLOR_UNION New; + + UINTN StartRow; + UINTN EndRow; + UINTN FStartRow; + UINTN Tmp; + + Orig = HMainEditor.ColorAttributes; + New.Data = 0; + New.Colors.Foreground = Orig.Colors.Background; + New.Colors.Background = Orig.Colors.Foreground; + + // + // if it's the first time after editor launch, so should refresh + // + if (HEditorFirst == FALSE) { + // + // no definite required refresh + // and file position displayed on screen has not been changed + // + if (!HBufferImageNeedRefresh && + !HBufferImageOnlyLineNeedRefresh && + HBufferImageBackupVar.LowVisibleRow == HBufferImage.LowVisibleRow + ) { + HBufferImageRestoreMousePosition (); + HBufferImageRestorePosition (); + return EFI_SUCCESS; + } + } + + gST->ConOut->EnableCursor (gST->ConOut, FALSE); + + // + // only need to refresh current line + // + if (HBufferImageOnlyLineNeedRefresh && HBufferImageBackupVar.LowVisibleRow == HBufferImage.LowVisibleRow) { + + HBufferImagePrintLine ( + HBufferImage.CurrentLine, + HBufferImage.DisplayPosition.Row, + HBufferImage.BufferPosition.Row, + Orig, + New + ); + } else { + // + // the whole edit area need refresh + // + if (HEditorMouseAction && HMainEditor.SelectStart != 0 && HMainEditor.SelectEnd != 0) { + if (HMainEditor.SelectStart != HMainEditorBackupVar.SelectStart) { + if (HMainEditor.SelectStart >= HMainEditorBackupVar.SelectStart && HMainEditorBackupVar.SelectStart != 0) { + StartRow = (HMainEditorBackupVar.SelectStart - 1) / 0x10 + 1; + } else { + StartRow = (HMainEditor.SelectStart - 1) / 0x10 + 1; + } + } else { + StartRow = (HMainEditor.SelectStart - 1) / 0x10 + 1; + } + + if (HMainEditor.SelectEnd <= HMainEditorBackupVar.SelectEnd) { + EndRow = (HMainEditorBackupVar.SelectEnd - 1) / 0x10 + 1; + } else { + EndRow = (HMainEditor.SelectEnd - 1) / 0x10 + 1; + } + // + // swap + // + if (StartRow > EndRow) { + Tmp = StartRow; + StartRow = EndRow; + EndRow = Tmp; + } + + FStartRow = StartRow; + + StartRow = 2 + StartRow - HBufferImage.LowVisibleRow; + EndRow = 2 + EndRow - HBufferImage.LowVisibleRow; + + } else { + // + // not mouse selection actions + // + FStartRow = HBufferImage.LowVisibleRow; + StartRow = 2; + EndRow = (HMainEditor.ScreenSize.Row - 1); + } + // + // no line + // + if (HBufferImage.Lines == NULL) { + HBufferImageRestoreMousePosition (); + HBufferImageRestorePosition (); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + return EFI_SUCCESS; + } + // + // get the first line that will be displayed + // + Line = HMoveLine (FStartRow - HBufferImage.BufferPosition.Row); + if (Line == NULL) { + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + return EFI_LOAD_ERROR; + } + + Link = &(Line->Link); + Row = StartRow; + do { + Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); + + // + // print line at row + // + HBufferImagePrintLine ( + Line, + Row, + HBufferImage.LowVisibleRow + Row - 2, + Orig, + New + ); + + Link = Link->ForwardLink; + Row++; + } while (Link != HBufferImage.ListHead && Row <= EndRow); + + while (Row <= EndRow) { + EditorClearLine (Row, HMainEditor.ScreenSize.Column, HMainEditor.ScreenSize.Row); + Row++; + } + // + // while not file end and not screen full + // + } + + HBufferImageRestoreMousePosition (); + HBufferImageRestorePosition (); + + HBufferImageNeedRefresh = FALSE; + HBufferImageOnlyLineNeedRefresh = FALSE; + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + + return EFI_SUCCESS; +} + +/** + Read an image into a buffer friom a source. + + @param[in] FileName Pointer to the file name. OPTIONAL and ignored if not FileTypeFileBuffer. + @param[in] DiskName Pointer to the disk name. OPTIONAL and ignored if not FileTypeDiskBuffer. + @param[in] DiskOffset Offset into the disk. OPTIONAL and ignored if not FileTypeDiskBuffer. + @param[in] DiskSize Size of the disk buffer. OPTIONAL and ignored if not FileTypeDiskBuffer. + @param[in] MemOffset Offset into the Memory. OPTIONAL and ignored if not FileTypeMemBuffer. + @param[in] MemSize Size of the Memory buffer. OPTIONAL and ignored if not FileTypeMemBuffer. + @param[in] BufferType The type of buffer to save. IGNORED. + @param[in] Recover TRUE for recovermode, FALSE otherwise. + + @return EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HBufferImageRead ( + IN CONST CHAR16 *FileName, + IN CONST CHAR16 *DiskName, + IN UINTN DiskOffset, + IN UINTN DiskSize, + IN UINTN MemOffset, + IN UINTN MemSize, + IN EDIT_FILE_TYPE BufferType, + IN BOOLEAN Recover + ) +{ + EFI_STATUS Status; + EDIT_FILE_TYPE BufferTypeBackup; + + // + // variable initialization + // + Status = EFI_SUCCESS; + HBufferImage.BufferType = BufferType; + + // + // three types of buffer supported + // file buffer + // disk buffer + // memory buffer + // + BufferTypeBackup = HBufferImage.BufferType; + + switch (BufferType) { + case FileTypeFileBuffer: + Status = HFileImageRead (FileName, Recover); + break; + + case FileTypeDiskBuffer: + Status = HDiskImageRead (DiskName, DiskOffset, DiskSize, Recover); + break; + + case FileTypeMemBuffer: + Status = HMemImageRead (MemOffset, MemSize, Recover); + break; + + default: + Status = EFI_NOT_FOUND; + break; + } + + if (EFI_ERROR (Status)) { + HBufferImage.BufferType = BufferTypeBackup; + } + + return Status; +} + +/** + Save the current image. + + @param[in] FileName Pointer to the file name. OPTIONAL and ignored if not FileTypeFileBuffer. + @param[in] DiskName Pointer to the disk name. OPTIONAL and ignored if not FileTypeDiskBuffer. + @param[in] DiskOffset Offset into the disk. OPTIONAL and ignored if not FileTypeDiskBuffer. + @param[in] DiskSize Size of the disk buffer. OPTIONAL and ignored if not FileTypeDiskBuffer. + @param[in] MemOffset Offset into the Memory. OPTIONAL and ignored if not FileTypeMemBuffer. + @param[in] MemSize Size of the Memory buffer. OPTIONAL and ignored if not FileTypeMemBuffer. + @param[in] BufferType The type of buffer to save. IGNORED. + + @return EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HBufferImageSave ( + IN CHAR16 *FileName, + IN CHAR16 *DiskName, + IN UINTN DiskOffset, + IN UINTN DiskSize, + IN UINTN MemOffset, + IN UINTN MemSize, + IN EDIT_FILE_TYPE BufferType + ) +{ + EFI_STATUS Status; + EDIT_FILE_TYPE BufferTypeBackup; + + // + // variable initialization + // + Status = EFI_SUCCESS; + BufferTypeBackup = HBufferImage.BufferType; + + switch (HBufferImage.BufferType) { + // + // file buffer + // + case FileTypeFileBuffer: + Status = HFileImageSave (FileName); + break; + + // + // disk buffer + // + case FileTypeDiskBuffer: + Status = HDiskImageSave (DiskName, DiskOffset, DiskSize); + break; + + // + // memory buffer + // + case FileTypeMemBuffer: + Status = HMemImageSave (MemOffset, MemSize); + break; + + default: + Status = EFI_NOT_FOUND; + break; + } + + if (EFI_ERROR (Status)) { + HBufferImage.BufferType = BufferTypeBackup; + } + + return Status; +} + +/** + Create a new line and append it to the line list. + Fields affected: + NumLines + Lines + + @retval NULL create line failed. + @return the line created. + +**/ +HEFI_EDITOR_LINE * +HBufferImageCreateLine ( + VOID + ) +{ + HEFI_EDITOR_LINE *Line; + + // + // allocate for line structure + // + Line = AllocateZeroPool (sizeof (HEFI_EDITOR_LINE)); + if (Line == NULL) { + return NULL; + } + + Line->Signature = EFI_EDITOR_LINE_LIST; + Line->Size = 0; + + HBufferImage.NumLines++; + + // + // insert to line list + // + InsertTailList (HBufferImage.ListHead, &Line->Link); + + if (HBufferImage.Lines == NULL) { + HBufferImage.Lines = CR ( + HBufferImage.ListHead->ForwardLink, + HEFI_EDITOR_LINE, + Link, + EFI_EDITOR_LINE_LIST + ); + } + + return Line; +} + +/** + Free the current image. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HBufferImageFree ( + VOID + ) +{ + // + // free all lines + // + HBufferImageFreeLines (); + + return EFI_SUCCESS; +} + +/** + change char to int value based on Hex. + + @param[in] Char The input char. + + @return The character's index value. + @retval -1 The operation failed. +**/ +INTN +HBufferImageCharToHex ( + IN CHAR16 Char + ) +{ + // + // change the character to hex + // + if (Char >= L'0' && Char <= L'9') { + return (Char - L'0'); + } + + if (Char >= L'a' && Char <= L'f') { + return (Char - L'a' + 10); + } + + if (Char >= L'A' && Char <= L'F') { + return (Char - L'A' + 10); + } + + return -1; +} + +/** + Add character. + + @param[in] Char -- input char. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +HBufferImageAddChar ( + IN CHAR16 Char + ) +{ + HEFI_EDITOR_LINE *Line; + HEFI_EDITOR_LINE *NewLine; + INTN Value; + UINT8 Old; + UINTN FRow; + UINTN FCol; + BOOLEAN High; + + Value = HBufferImageCharToHex (Char); + + // + // invalid input + // + if (Value == -1) { + return EFI_SUCCESS; + } + + Line = HBufferImage.CurrentLine; + FRow = HBufferImage.BufferPosition.Row; + FCol = HBufferImage.BufferPosition.Column; + High = HBufferImage.HighBits; + + // + // only needs to refresh current line + // + HBufferImageOnlyLineNeedRefresh = TRUE; + + // + // not a full line and beyond the last character + // + if (FCol > Line->Size) { + // + // cursor always at high 4 bits + // and always put input to the low 4 bits + // + Line->Buffer[Line->Size] = (UINT8) Value; + Line->Size++; + High = FALSE; + } else { + + Old = Line->Buffer[FCol - 1]; + + // + // always put the input to the low 4 bits + // + Old = (UINT8) (Old & 0x0f); + Old = (UINT8) (Old << 4); + Old = (UINT8) (Value + Old); + Line->Buffer[FCol - 1] = Old; + + // + // at the low 4 bits of the last character of a full line + // so if no next line, need to create a new line + // + if (!High && FCol == 0x10) { + + HBufferImageOnlyLineNeedRefresh = FALSE; + HBufferImageNeedRefresh = TRUE; + + if (Line->Link.ForwardLink == HBufferImage.ListHead) { + // + // last line + // + // create a new line + // + NewLine = HBufferImageCreateLine (); + if (NewLine == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // end of NULL + // + } + // + // end of == ListHead + // + } + // + // end of == 0x10 + // + // if already at end of this line, scroll it to the start of next line + // + if (FCol == 0x10 && !High) { + // + // definitely has next line + // + FRow++; + FCol = 1; + High = TRUE; + } else { + // + // if not at end of this line, just move to next column + // + if (!High) { + FCol++; + } + + if (High) { + High = FALSE; + } else { + High = TRUE; + } + + } + // + // end of ==FALSE + // + } + // + // move cursor to right + // + HBufferImageMovePosition (FRow, FCol, High); + + if (!HBufferImage.Modified) { + HBufferImage.Modified = TRUE; + } + + return EFI_SUCCESS; +} + +/** + Delete the previous character. + + @retval EFI_SUCCESS The operationw as successful. +**/ +EFI_STATUS +HBufferImageDoBackspace ( + VOID + ) +{ + HEFI_EDITOR_LINE *Line; + + UINTN FileColumn; + UINTN FPos; + BOOLEAN LastLine; + + // + // variable initialization + // + LastLine = FALSE; + + // + // already the first character + // + if (HBufferImage.BufferPosition.Row == 1 && HBufferImage.BufferPosition.Column == 1) { + return EFI_SUCCESS; + } + + FPos = (HBufferImage.BufferPosition.Row - 1) * 0x10 + HBufferImage.BufferPosition.Column - 1; + + FileColumn = HBufferImage.BufferPosition.Column; + + Line = HBufferImage.CurrentLine; + LastLine = FALSE; + if (Line->Link.ForwardLink == HBufferImage.ListHead && FileColumn > 1) { + LastLine = TRUE; + } + + HBufferImageDeleteCharacterFromBuffer (FPos - 1, 1, NULL); + + // + // if is the last line + // then only this line need to be refreshed + // + if (LastLine) { + HBufferImageNeedRefresh = FALSE; + HBufferImageOnlyLineNeedRefresh = TRUE; + } else { + HBufferImageNeedRefresh = TRUE; + HBufferImageOnlyLineNeedRefresh = FALSE; + } + + if (!HBufferImage.Modified) { + HBufferImage.Modified = TRUE; + } + + return EFI_SUCCESS; +} + +/** + ASCII key + Backspace + return. + + @param[in] Char The input char. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A load error occurred. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +HBufferImageDoCharInput ( + IN CHAR16 Char + ) +{ + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + switch (Char) { + case 0: + break; + + case 0x08: + Status = HBufferImageDoBackspace (); + break; + + case 0x09: + case 0x0a: + case 0x0d: + // + // Tabs, Returns are thought as nothing + // + break; + + default: + // + // DEAL WITH ASCII CHAR, filter out thing like ctrl+f + // + if (Char > 127 || Char < 32) { + Status = StatusBarSetStatusString (L"Unknown Command"); + } else { + Status = HBufferImageAddChar (Char); + } + + break; + } + + return Status; +} + +/** + Check user specified FileRow is above current screen. + + @param[in] FileRow Row of file position ( start from 1 ). + + @retval TRUE It is above the current screen. + @retval FALSE It is not above the current screen. + +**/ +BOOLEAN +HAboveCurrentScreen ( + IN UINTN FileRow + ) +{ + if (FileRow < HBufferImage.LowVisibleRow) { + return TRUE; + } + + return FALSE; +} + +/** + Check user specified FileRow is under current screen. + + @param[in] FileRow Row of file position ( start from 1 ). + + @retval TRUE It is under the current screen. + @retval FALSE It is not under the current screen. + +**/ +BOOLEAN +HUnderCurrentScreen ( + IN UINTN FileRow + ) +{ + if (FileRow > HBufferImage.LowVisibleRow + (HMainEditor.ScreenSize.Row - 2) - 1) { + return TRUE; + } + + return FALSE; +} + +/** + According to cursor's file position, adjust screen display. + + @param[in] NewFilePosRow Row of file position ( start from 1 ). + @param[in] NewFilePosCol Column of file position ( start from 1 ). + @param[in] HighBits Cursor will on high4 bits or low4 bits. +**/ +VOID +HBufferImageMovePosition ( + IN UINTN NewFilePosRow, + IN UINTN NewFilePosCol, + IN BOOLEAN HighBits + ) +{ + INTN RowGap; + UINTN Abs; + BOOLEAN Above; + BOOLEAN Under; + UINTN NewDisplayCol; + + // + // CALCULATE gap between current file position and new file position + // + RowGap = NewFilePosRow - HBufferImage.BufferPosition.Row; + + Under = HUnderCurrentScreen (NewFilePosRow); + Above = HAboveCurrentScreen (NewFilePosRow); + + HBufferImage.HighBits = HighBits; + + // + // if is below current screen + // + if (Under) { + // + // display row will be unchanged + // + HBufferImage.BufferPosition.Row = NewFilePosRow; + } else { + if (Above) { + // + // has enough above line, so display row unchanged + // not has enough above lines, so the first line is + // at the first display line + // + if (NewFilePosRow < (HBufferImage.DisplayPosition.Row - 2 + 1)) { + HBufferImage.DisplayPosition.Row = NewFilePosRow + 2 - 1; + } + + HBufferImage.BufferPosition.Row = NewFilePosRow; + } else { + // + // in current screen + // + HBufferImage.BufferPosition.Row = NewFilePosRow; + if (RowGap <= 0) { + Abs = (UINTN)ABS(RowGap); + HBufferImage.DisplayPosition.Row -= Abs; + } else { + HBufferImage.DisplayPosition.Row += RowGap; + } + + } + } + + HBufferImage.LowVisibleRow = HBufferImage.BufferPosition.Row - (HBufferImage.DisplayPosition.Row - 2); + + // + // always in current screen + // + HBufferImage.BufferPosition.Column = NewFilePosCol; + + NewDisplayCol = 10 + (NewFilePosCol - 1) * 3; + if (NewFilePosCol > 0x8) { + NewDisplayCol++; + } + + if (!HighBits) { + NewDisplayCol++; + } + + HBufferImage.DisplayPosition.Column = NewDisplayCol; + + // + // let CurrentLine point to correct line; + // + HBufferImage.CurrentLine = HMoveCurrentLine (RowGap); + +} + +/** + Scroll cursor to right. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HBufferImageScrollRight ( + VOID + ) +{ + HEFI_EDITOR_LINE *Line; + UINTN FRow; + UINTN FCol; + + // + // scroll right will always move to the high4 bits of the next character + // + HBufferImageNeedRefresh = FALSE; + HBufferImageOnlyLineNeedRefresh = FALSE; + + Line = HBufferImage.CurrentLine; + + FRow = HBufferImage.BufferPosition.Row; + FCol = HBufferImage.BufferPosition.Column; + + // + // this line is not full and no next line + // + if (FCol > Line->Size) { + return EFI_SUCCESS; + } + // + // if already at end of this line, scroll it to the start of next line + // + if (FCol == 0x10) { + // + // has next line + // + if (Line->Link.ForwardLink != HBufferImage.ListHead) { + FRow++; + FCol = 1; + + } else { + return EFI_SUCCESS; + } + } else { + // + // if not at end of this line, just move to next column + // + FCol++; + + } + + HBufferImageMovePosition (FRow, FCol, TRUE); + + return EFI_SUCCESS; +} + +/** + Scroll cursor to left. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HBufferImageScrollLeft ( + VOID + ) +{ + + HEFI_EDITOR_LINE *Line; + UINTN FRow; + UINTN FCol; + + HBufferImageNeedRefresh = FALSE; + HBufferImageOnlyLineNeedRefresh = FALSE; + + Line = HBufferImage.CurrentLine; + + FRow = HBufferImage.BufferPosition.Row; + FCol = HBufferImage.BufferPosition.Column; + + // + // if already at start of this line, so move to the end of previous line + // + if (FCol <= 1) { + // + // has previous line + // + if (Line->Link.BackLink != HBufferImage.ListHead) { + FRow--; + Line = CR (Line->Link.BackLink, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); + FCol = Line->Size; + } else { + return EFI_SUCCESS; + } + } else { + // + // if not at start of this line, just move to previous column + // + FCol--; + } + + HBufferImageMovePosition (FRow, FCol, TRUE); + + return EFI_SUCCESS; +} + +/** + Scroll cursor to the next line + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HBufferImageScrollDown ( + VOID + ) +{ + HEFI_EDITOR_LINE *Line; + UINTN FRow; + UINTN FCol; + BOOLEAN HighBits; + + Line = HBufferImage.CurrentLine; + + FRow = HBufferImage.BufferPosition.Row; + FCol = HBufferImage.BufferPosition.Column; + HighBits = HBufferImage.HighBits; + + // + // has next line + // + if (Line->Link.ForwardLink != HBufferImage.ListHead) { + FRow++; + Line = CR (Line->Link.ForwardLink, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); + + // + // if the next line is not that long, so move to end of next line + // + if (FCol > Line->Size) { + FCol = Line->Size + 1; + HighBits = TRUE; + } + + } else { + return EFI_SUCCESS; + } + + HBufferImageMovePosition (FRow, FCol, HighBits); + + return EFI_SUCCESS; +} + +/** + Scroll cursor to previous line + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HBufferImageScrollUp ( + VOID + ) +{ + HEFI_EDITOR_LINE *Line; + UINTN FRow; + UINTN FCol; + + Line = HBufferImage.CurrentLine; + + FRow = HBufferImage.BufferPosition.Row; + FCol = HBufferImage.BufferPosition.Column; + + // + // has previous line + // + if (Line->Link.BackLink != HBufferImage.ListHead) { + FRow--; + + } else { + return EFI_SUCCESS; + } + + HBufferImageMovePosition (FRow, FCol, HBufferImage.HighBits); + + return EFI_SUCCESS; +} + +/** + Scroll cursor to next page + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HBufferImagePageDown ( + VOID + ) +{ + HEFI_EDITOR_LINE *Line; + UINTN FRow; + UINTN FCol; + UINTN Gap; + BOOLEAN HighBits; + + Line = HBufferImage.CurrentLine; + + FRow = HBufferImage.BufferPosition.Row; + FCol = HBufferImage.BufferPosition.Column; + HighBits = HBufferImage.HighBits; + + // + // has next page + // + if (HBufferImage.NumLines >= FRow + (HMainEditor.ScreenSize.Row - 2)) { + Gap = (HMainEditor.ScreenSize.Row - 2); + } else { + // + // MOVE CURSOR TO LAST LINE + // + Gap = HBufferImage.NumLines - FRow; + } + // + // get correct line + // + Line = HMoveLine (Gap); + + // + // if that line, is not that long, so move to the end of that line + // + if (Line != NULL && FCol > Line->Size) { + FCol = Line->Size + 1; + HighBits = TRUE; + } + + FRow += Gap; + + HBufferImageMovePosition (FRow, FCol, HighBits); + + return EFI_SUCCESS; +} + +/** + Scroll cursor to previous page + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HBufferImagePageUp ( + VOID + ) +{ + UINTN FRow; + UINTN FCol; + UINTN Gap; + INTN Retreat; + + FRow = HBufferImage.BufferPosition.Row; + FCol = HBufferImage.BufferPosition.Column; + + // + // has previous page + // + if (FRow > (HMainEditor.ScreenSize.Row - 2)) { + Gap = (HMainEditor.ScreenSize.Row - 2); + } else { + // + // the first line of file will displayed on the first line of screen + // + Gap = FRow - 1; + } + + Retreat = Gap; + Retreat = -Retreat; + + FRow -= Gap; + + HBufferImageMovePosition (FRow, FCol, HBufferImage.HighBits); + + return EFI_SUCCESS; +} + +/** + Scroll cursor to start of line + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HBufferImageHome ( + VOID + ) +{ + UINTN FRow; + UINTN FCol; + BOOLEAN HighBits; + + // + // curosr will at the high bit + // + FRow = HBufferImage.BufferPosition.Row; + FCol = 1; + HighBits = TRUE; + + // + // move cursor position + // + HBufferImageMovePosition (FRow, FCol, HighBits); + + return EFI_SUCCESS; +} + +/** + Scroll cursor to end of line. + + @retval EFI_SUCCESS Teh operation was successful. +**/ +EFI_STATUS +HBufferImageEnd ( + VOID + ) +{ + HEFI_EDITOR_LINE *Line; + UINTN FRow; + UINTN FCol; + BOOLEAN HighBits; + + // + // need refresh mouse + // + HBufferImageMouseNeedRefresh = TRUE; + + Line = HBufferImage.CurrentLine; + + FRow = HBufferImage.BufferPosition.Row; + + if (Line->Size == 0x10) { + FCol = Line->Size; + HighBits = FALSE; + } else { + FCol = Line->Size + 1; + HighBits = TRUE; + } + // + // move cursor position + // + HBufferImageMovePosition (FRow, FCol, HighBits); + + return EFI_SUCCESS; +} + +/** + Get the size of the open buffer. + + @retval The size in bytes. +**/ +UINTN +HBufferImageGetTotalSize ( + VOID + ) +{ + UINTN Size; + + HEFI_EDITOR_LINE *Line; + + // + // calculate the total size of whole line list's buffer + // + if (HBufferImage.Lines == NULL) { + return 0; + } + + Line = CR ( + HBufferImage.ListHead->BackLink, + HEFI_EDITOR_LINE, + Link, + EFI_EDITOR_LINE_LIST + ); + // + // one line at most 0x10 + // + Size = 0x10 * (HBufferImage.NumLines - 1) + Line->Size; + + return Size; +} + +/** + Delete character from buffer. + + @param[in] Pos Position, Pos starting from 0. + @param[in] Count The Count of characters to delete. + @param[out] DeleteBuffer The DeleteBuffer. + + @retval EFI_SUCCESS Success +**/ +EFI_STATUS +HBufferImageDeleteCharacterFromBuffer ( + IN UINTN Pos, + IN UINTN Count, + OUT UINT8 *DeleteBuffer + ) +{ + UINTN Index; + + VOID *Buffer; + UINT8 *BufferPtr; + UINTN Size; + + HEFI_EDITOR_LINE *Line; + LIST_ENTRY *Link; + + UINTN OldFCol; + UINTN OldFRow; + UINTN OldPos; + + UINTN NewPos; + + EFI_STATUS Status; + + Size = HBufferImageGetTotalSize (); + + if (Size < Count) { + return EFI_LOAD_ERROR; + } + + if (Size == 0) { + return EFI_SUCCESS; + } + + // + // relocate all the HBufferImage fields + // + OldFRow = HBufferImage.BufferPosition.Row; + OldFCol = HBufferImage.BufferPosition.Column; + OldPos = (OldFRow - 1) * 0x10 + OldFCol - 1; + + if (Pos > 0) { + // + // has character before it, + // so locate according to block's previous character + // + NewPos = Pos - 1; + + } else { + // + // has no character before it, + // so locate according to block's next character + // + NewPos = 0; + } + + HBufferImageMovePosition (NewPos / 0x10 + 1, NewPos % 0x10 + 1, TRUE); + + Buffer = AllocateZeroPool (Size); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + HBufferImageListToBuffer (Buffer, Size); + + BufferPtr = (UINT8 *) Buffer; + + // + // pass deleted buffer out + // + if (DeleteBuffer != NULL) { + for (Index = 0; Index < Count; Index++) { + DeleteBuffer[Index] = BufferPtr[Pos + Index]; + } + } + // + // delete the part from Pos + // + for (Index = Pos; Index < Size - Count; Index++) { + BufferPtr[Index] = BufferPtr[Index + Count]; + } + + Size -= Count; + + HBufferImageFreeLines (); + + Status = HBufferImageBufferToList (Buffer, Size); + FreePool (Buffer); + + if (EFI_ERROR (Status)) { + return Status; + } + + Link = HMainEditor.BufferImage->ListHead->ForwardLink; + for (Index = 0; Index < NewPos / 0x10; Index++) { + Link = Link->ForwardLink; + } + + Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); + HBufferImage.CurrentLine = Line; + + // + // if current cursor position if inside select area + // then move it to the block's NEXT character + // + if (OldPos >= Pos && OldPos < (Pos + Count)) { + NewPos = Pos; + } else { + if (OldPos < Pos) { + NewPos = OldPos; + } else { + NewPos = OldPos - Count; + } + } + + HBufferImageMovePosition (NewPos / 0x10 + 1, NewPos % 0x10 + 1, TRUE); + + return EFI_SUCCESS; +} + +/** + Add character to buffer, add before pos. + + @param[in] Pos Position, Pos starting from 0. + @param[in] Count Count of characters to add. + @param[in] AddBuffer Add buffer. + + @retval EFI_SUCCESS Success. +**/ +EFI_STATUS +HBufferImageAddCharacterToBuffer ( + IN UINTN Pos, + IN UINTN Count, + IN UINT8 *AddBuffer + ) +{ + INTN Index; + + VOID *Buffer; + UINT8 *BufferPtr; + UINTN Size; + + HEFI_EDITOR_LINE *Line; + + LIST_ENTRY *Link; + + UINTN OldFCol; + UINTN OldFRow; + UINTN OldPos; + + UINTN NewPos; + + Size = HBufferImageGetTotalSize (); + + // + // relocate all the HBufferImage fields + // + OldFRow = HBufferImage.BufferPosition.Row; + OldFCol = HBufferImage.BufferPosition.Column; + OldPos = (OldFRow - 1) * 0x10 + OldFCol - 1; + + // + // move cursor before Pos + // + if (Pos > 0) { + NewPos = Pos - 1; + } else { + NewPos = 0; + } + + HBufferImageMovePosition (NewPos / 0x10 + 1, NewPos % 0x10 + 1, TRUE); + + Buffer = AllocateZeroPool (Size + Count); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + HBufferImageListToBuffer (Buffer, Size); + + BufferPtr = (UINT8 *) Buffer; + + // + // get a place to add + // + for (Index = (INTN) (Size + Count - 1); Index >= (INTN) Pos; Index--) { + BufferPtr[Index] = BufferPtr[Index - Count]; + } + // + // add the buffer + // + for (Index = (INTN) 0; Index < (INTN) Count; Index++) { + BufferPtr[Index + Pos] = AddBuffer[Index]; + } + + Size += Count; + + HBufferImageFreeLines (); + + HBufferImageBufferToList (Buffer, Size); + + FreePool (Buffer); + + Link = HMainEditor.BufferImage->ListHead->ForwardLink; + for (Index = 0; Index < (INTN) NewPos / 0x10; Index++) { + Link = Link->ForwardLink; + } + + Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); + HBufferImage.CurrentLine = Line; + + if (OldPos >= Pos) { + NewPos = OldPos + Count; + } else { + NewPos = OldPos; + } + + HBufferImageMovePosition (NewPos / 0x10 + 1, NewPos % 0x10 + 1, TRUE); + + return EFI_SUCCESS; +} + +/** + Delete current character from line. + + @retval EFI_SUCCESS The operationw as successful. +**/ +EFI_STATUS +HBufferImageDoDelete ( + VOID + ) +{ + + HEFI_EDITOR_LINE *Line; + + BOOLEAN LastLine; + UINTN FileColumn; + UINTN FPos; + + FPos = (HBufferImage.BufferPosition.Row - 1) * 0x10 + HBufferImage.BufferPosition.Column - 1; + + FileColumn = HBufferImage.BufferPosition.Column; + + Line = HBufferImage.CurrentLine; + + // + // if beyond the last character + // + if (FileColumn > Line->Size) { + return EFI_SUCCESS; + } + + LastLine = FALSE; + if (Line->Link.ForwardLink == HBufferImage.ListHead) { + LastLine = TRUE; + } + + HBufferImageDeleteCharacterFromBuffer (FPos, 1, NULL); + + // + // if is the last line + // then only this line need to be refreshed + // + if (LastLine) { + HBufferImageNeedRefresh = FALSE; + HBufferImageOnlyLineNeedRefresh = TRUE; + } else { + HBufferImageNeedRefresh = TRUE; + HBufferImageOnlyLineNeedRefresh = FALSE; + } + + if (!HBufferImage.Modified) { + HBufferImage.Modified = TRUE; + } + + return EFI_SUCCESS; +} + +/** + Change the raw buffer to a list of lines for the UI. + + @param[in] Buffer The pointer to the buffer to fill. + @param[in] Bytes The size of the buffer in bytes. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +HBufferImageBufferToList ( + IN VOID *Buffer, + IN UINTN Bytes + ) +{ + UINTN TempI; + UINTN TempJ; + UINTN Left; + HEFI_EDITOR_LINE *Line; + UINT8 *BufferPtr; + + TempI = 0; + Left = 0; + BufferPtr = (UINT8 *) Buffer; + + // + // parse file content line by line + // + while (TempI < Bytes) { + if (Bytes - TempI >= 0x10) { + Left = 0x10; + } else { + Left = Bytes - TempI; + } + + // + // allocate a new line + // + Line = HBufferImageCreateLine (); + if (Line == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Line->Size = Left; + + for (TempJ = 0; TempJ < Left; TempJ++) { + Line->Buffer[TempJ] = BufferPtr[TempI]; + TempI++; + } + + } + + // + // last line is a full line, SO create a new line + // + if (Left == 0x10 || Bytes == 0) { + Line = HBufferImageCreateLine (); + if (Line == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + return EFI_SUCCESS; +} + +/** + Change the list of lines from the UI to a raw buffer. + + @param[in] Buffer The pointer to the buffer to fill. + @param[in] Bytes The size of the buffer in bytes. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HBufferImageListToBuffer ( + IN VOID *Buffer, + IN UINTN Bytes + ) +{ + UINTN Count; + UINTN Index; + HEFI_EDITOR_LINE *Line; + LIST_ENTRY *Link; + UINT8 *BufferPtr; + + // + // change the line list to a large buffer + // + if (HBufferImage.Lines == NULL) { + return EFI_SUCCESS; + } + + Link = &HBufferImage.Lines->Link; + Count = 0; + BufferPtr = (UINT8 *) Buffer; + + // + // deal line by line + // + while (Link != HBufferImage.ListHead) { + + Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); + + //@todo shouldn't this be an error??? + if (Count + Line->Size > Bytes) { + return EFI_SUCCESS; + } + + for (Index = 0; Index < Line->Size; Index++) { + BufferPtr[Index] = Line->Buffer[Index]; + } + + Count += Line->Size; + BufferPtr += Line->Size; + + Link = Link->ForwardLink; + } + + return EFI_SUCCESS; +} + +/** + Move the mouse in the image buffer. + + @param[in] TextX The x-coordinate. + @param[in] TextY The y-coordinate. +**/ +VOID +HBufferImageAdjustMousePosition ( + IN INT32 TextX, + IN INT32 TextY + ) +{ + UINTN TempX; + UINTN TempY; + UINTN AbsX; + UINTN AbsY; + + // + // TextX and TextY is mouse movement data returned by mouse driver + // This function will change it to MousePosition + // + // + // get absolute TempX value + // + if (TextX >= 0) { + AbsX = TextX; + } else { + AbsX = -TextX; + } + // + // get absolute TempY value + // + if (TextY >= 0) { + AbsY = TextY; + } else { + AbsY = -TextY; + } + + TempX = HBufferImage.MousePosition.Column; + TempY = HBufferImage.MousePosition.Row; + + if (TextX >= 0) { + TempX += TextX; + } else { + if (TempX >= AbsX) { + TempX -= AbsX; + } else { + TempX = 0; + } + } + + if (TextY >= 0) { + TempY += TextY; + } else { + if (TempY >= AbsY) { + TempY -= AbsY; + } else { + TempY = 0; + } + } + // + // check whether new mouse column position is beyond screen + // if not, adjust it + // + if (TempX >= 10 && TempX <= (10 + 0x10 * 3 - 1)) { + HBufferImage.MousePosition.Column = TempX; + } else if (TempX < 10) { + HBufferImage.MousePosition.Column = 10; + } else if (TempX > (10 + 0x10 * 3 - 1)) { + HBufferImage.MousePosition.Column = 10 + 0x10 * 3 - 1; + } + // + // check whether new mouse row position is beyond screen + // if not, adjust it + // + if (TempY >= 2 && TempY <= (HMainEditor.ScreenSize.Row - 1)) { + HBufferImage.MousePosition.Row = TempY; + } else if (TempY < 2) { + HBufferImage.MousePosition.Row = 2; + } else if (TempY > (HMainEditor.ScreenSize.Row - 1)) { + HBufferImage.MousePosition.Row = (HMainEditor.ScreenSize.Row - 1); + } + +} + +/** + Dispatch input to different handler + + @param[in] Key The input key: + the keys can be: + ASCII KEY + Backspace/Delete + Direction key: up/down/left/right/pgup/pgdn + Home/End + INS + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A load error occurred. + @retval EFI_OUT_OF_RESOURCES A Memory allocation failed. +**/ +EFI_STATUS +HBufferImageHandleInput ( + IN EFI_INPUT_KEY *Key + ) +{ + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + switch (Key->ScanCode) { + // + // ordinary key + // + case SCAN_NULL: + Status = HBufferImageDoCharInput (Key->UnicodeChar); + break; + + // + // up arrow + // + case SCAN_UP: + Status = HBufferImageScrollUp (); + break; + + // + // down arrow + // + case SCAN_DOWN: + Status = HBufferImageScrollDown (); + break; + + // + // right arrow + // + case SCAN_RIGHT: + Status = HBufferImageScrollRight (); + break; + + // + // left arrow + // + case SCAN_LEFT: + Status = HBufferImageScrollLeft (); + break; + + // + // page up + // + case SCAN_PAGE_UP: + Status = HBufferImagePageUp (); + break; + + // + // page down + // + case SCAN_PAGE_DOWN: + Status = HBufferImagePageDown (); + break; + + // + // delete + // + case SCAN_DELETE: + Status = HBufferImageDoDelete (); + break; + + // + // home + // + case SCAN_HOME: + Status = HBufferImageHome (); + break; + + // + // end + // + case SCAN_END: + Status = HBufferImageEnd (); + break; + + default: + Status = StatusBarSetStatusString (L"Unknown Command"); + break; + } + + return Status; +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/BufferImage.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/BufferImage.h new file mode 100644 index 00000000..082a9cb2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/BufferImage.h @@ -0,0 +1,267 @@ +/** @file + Defines BufferImage - the view of the file that is visible at any point, + as well as the event handlers for editing the file + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _LIB_BUFFER_IMAGE_H_ +#define _LIB_BUFFER_IMAGE_H_ + +#include "HexEditor.h" + +/** + Initialization function for HBufferImage + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HBufferImageInit ( + VOID + ); + +/** + Cleanup function for HBufferImage + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HBufferImageCleanup ( + VOID + ); + +/** + Refresh function for HBufferImage. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A Load error occurred. + +**/ +EFI_STATUS +HBufferImageRefresh ( + VOID + ); + +/** + Dispatch input to different handler + + @param[in] Key The input key: + the keys can be: + ASCII KEY + Backspace/Delete + Direction key: up/down/left/right/pgup/pgdn + Home/End + INS + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A load error occurred. + @retval EFI_OUT_OF_RESOURCES A Memory allocation failed. +**/ +EFI_STATUS +HBufferImageHandleInput ( + IN EFI_INPUT_KEY *Key + ); + +/** + Backup function for HBufferImage. Only a few fields need to be backup. + This is for making the file buffer refresh as few as possible. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HBufferImageBackup ( + VOID + ); + +/** + Read an image into a buffer friom a source. + + @param[in] FileName Pointer to the file name. OPTIONAL and ignored if not FileTypeFileBuffer. + @param[in] DiskName Pointer to the disk name. OPTIONAL and ignored if not FileTypeDiskBuffer. + @param[in] DiskOffset Offset into the disk. OPTIONAL and ignored if not FileTypeDiskBuffer. + @param[in] DiskSize Size of the disk buffer. OPTIONAL and ignored if not FileTypeDiskBuffer. + @param[in] MemOffset Offset into the Memory. OPTIONAL and ignored if not FileTypeMemBuffer. + @param[in] MemSize Size of the Memory buffer. OPTIONAL and ignored if not FileTypeMemBuffer. + @param[in] BufferType The type of buffer to save. IGNORED. + @param[in] Recover TRUE for recovermode, FALSE otherwise. + + @return EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HBufferImageRead ( + IN CONST CHAR16 *FileName, + IN CONST CHAR16 *DiskName, + IN UINTN DiskOffset, + IN UINTN DiskSize, + IN UINTN MemOffset, + IN UINTN MemSize, + IN EDIT_FILE_TYPE BufferType, + IN BOOLEAN Recover + ); + +/** + Save the current image. + + @param[in] FileName Pointer to the file name. OPTIONAL and ignored if not FileTypeFileBuffer. + @param[in] DiskName Pointer to the disk name. OPTIONAL and ignored if not FileTypeDiskBuffer. + @param[in] DiskOffset Offset into the disk. OPTIONAL and ignored if not FileTypeDiskBuffer. + @param[in] DiskSize Size of the disk buffer. OPTIONAL and ignored if not FileTypeDiskBuffer. + @param[in] MemOffset Offset into the Memory. OPTIONAL and ignored if not FileTypeMemBuffer. + @param[in] MemSize Size of the Memory buffer. OPTIONAL and ignored if not FileTypeMemBuffer. + @param[in] BufferType The type of buffer to save. IGNORED. + + @return EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HBufferImageSave ( + IN CHAR16 *FileName, + IN CHAR16 *DiskName, + IN UINTN DiskOffset, + IN UINTN DiskSize, + IN UINTN MemOffset, + IN UINTN MemSize, + IN EDIT_FILE_TYPE BufferType + ); + +/** + According to cursor's file position, adjust screen display. + + @param[in] NewFilePosRow Row of file position ( start from 1 ). + @param[in] NewFilePosCol Column of file position ( start from 1 ). + @param[in] HighBits Cursor will on high4 bits or low4 bits. +**/ +VOID +HBufferImageMovePosition ( + IN UINTN NewFilePosRow, + IN UINTN NewFilePosCol, + IN BOOLEAN HighBits + ); + + +/** + Create a new line and append it to the line list. + Fields affected: + NumLines + Lines + + @retval NULL create line failed. + @return the line created. + +**/ +HEFI_EDITOR_LINE * +HBufferImageCreateLine ( + VOID + ); + +/** + Free the current image. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HBufferImageFree ( + VOID + ); + +/** + Delete character from buffer. + + @param[in] Pos Position, Pos starting from 0. + @param[in] Count The Count of characters to delete. + @param[out] DeleteBuffer The DeleteBuffer. + + @retval EFI_SUCCESS Success +**/ +EFI_STATUS +HBufferImageDeleteCharacterFromBuffer ( + IN UINTN Pos, + IN UINTN Count, + OUT UINT8 *DeleteBuffer + ); + +/** + Add character to buffer, add before pos. + + @param[in] Pos Position, Pos starting from 0. + @param[in] Count Count of characters to add. + @param[in] AddBuffer Add buffer. + + @retval EFI_SUCCESS Success. +**/ +EFI_STATUS +HBufferImageAddCharacterToBuffer ( + IN UINTN Pos, + IN UINTN Count, + IN UINT8 *AddBuffer + ); + +/** + Change the raw buffer to a list of lines for the UI. + + @param[in] Buffer The pointer to the buffer to fill. + @param[in] Bytes The size of the buffer in bytes. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +HBufferImageBufferToList ( + IN VOID *Buffer, + IN UINTN Bytes + ); + +/** + Change the list of lines from the UI to a raw buffer. + + @param[in] Buffer The pointer to the buffer to fill. + @param[in] Bytes The size of the buffer in bytes. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HBufferImageListToBuffer ( + IN VOID *Buffer, + IN UINTN Bytes + ); + +/** + Move the mouse in the image buffer. + + @param[in] TextX The x-coordinate. + @param[in] TextY The y-coordinate. +**/ +VOID +HBufferImageAdjustMousePosition ( + IN INT32 TextX, + IN INT32 TextY + ); + +/** + Function to decide if a column number is stored in the high bits. + + @param[in] Column The column to examine. + @param[out] FCol The actual column number. + + @retval TRUE The actual column was in high bits and is now in FCol. + @retval FALSE There was not a column number in the high bits. +**/ +BOOLEAN +HBufferImageIsAtHighBits ( + IN UINTN Column, + OUT UINTN *FCol + ); + +/** + Get the size of the open buffer. + + @retval The size in bytes. +**/ +UINTN +HBufferImageGetTotalSize ( + VOID + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Clipboard.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Clipboard.c new file mode 100644 index 00000000..5de75a6b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Clipboard.c @@ -0,0 +1,106 @@ +/** @file + Functions to deal with Clip Board + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "HexEditor.h" + +typedef struct { + UINT8 *Buffer; + UINTN Size; +} HEFI_EDITOR_CLIPBOARD; + +HEFI_EDITOR_CLIPBOARD HClipBoard; + +// +// for basic initialization of HClipBoard +// +HEFI_EDITOR_CLIPBOARD HClipBoardConst = { + NULL, + 0 +}; + +/** + Initialization function for HDiskImage. + + @param[in] EFI_SUCCESS The operation was successful. + @param[in] EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HClipBoardInit ( + VOID + ) +{ + // + // basiclly initialize the HDiskImage + // + CopyMem (&HClipBoard, &HClipBoardConst, sizeof (HClipBoard)); + + return EFI_SUCCESS; +} + +/** + Initialization function for HDiskImage. + + @param[in] EFI_SUCCESS The operation was successful. + @param[in] EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HClipBoardCleanup ( + VOID + ) +{ + + SHELL_FREE_NON_NULL (HClipBoard.Buffer); + + return EFI_SUCCESS; +} + +/** + Set a buffer into the clipboard. + + @param[in] Buffer The buffer to add to the clipboard. + @param[in] Size The size of Buffer in bytes. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HClipBoardSet ( + IN UINT8 *Buffer, + IN UINTN Size + ) +{ + // + // free the old clipboard buffer + // and set new clipboard buffer + // + SHELL_FREE_NON_NULL (HClipBoard.Buffer); + HClipBoard.Buffer = Buffer; + + HClipBoard.Size = Size; + + return EFI_SUCCESS; +} + +/** + Get a buffer from the clipboard. + + @param[out] Buffer The pointer to the buffer to add to the clipboard. + + @return the size of the buffer. +**/ +UINTN +HClipBoardGet ( + OUT UINT8 **Buffer + ) +{ + // + // return the clipboard buffer + // + *Buffer = HClipBoard.Buffer; + + return HClipBoard.Size; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Clipboard.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Clipboard.h new file mode 100644 index 00000000..6408ae0e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Clipboard.h @@ -0,0 +1,63 @@ +/** @file + Defines DiskImage - the view of the file that is visible at any point, + as well as the event handlers for editing the file + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _LIB_CLIP_BOARD_H_ +#define _LIB_CLIP_BOARD_H_ + +#include "HexEditor.h" + +/** + Initialization function for HDiskImage + + @param[in] EFI_SUCCESS The operation was successful. + @param[in] EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HClipBoardInit ( + VOID + ); + +/** + Initialization function for HDiskImage. + + @param[in] EFI_SUCCESS The operation was successful. + @param[in] EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HClipBoardCleanup ( + VOID + ); + +/** + Set a buffer into the clipboard. + + @param[in] Buffer The buffer to add to the clipboard. + @param[in] Size The size of Buffer in bytes. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HClipBoardSet ( + IN UINT8 *Buffer, + IN UINTN Size + ); + +/** + Get a buffer from the clipboard. + + @param[out] Buffer The pointer to the buffer to add to the clipboard. + + @return the size of the buffer. +**/ +UINTN +HClipBoardGet ( + OUT UINT8 **Buffer + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/DiskImage.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/DiskImage.c new file mode 100644 index 00000000..80f614c6 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/DiskImage.c @@ -0,0 +1,411 @@ +/** @file + Functions to deal with Disk buffer. + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "HexEditor.h" +#include + +extern EFI_HANDLE HImageHandleBackup; +extern HEFI_EDITOR_BUFFER_IMAGE HBufferImage; + +extern BOOLEAN HBufferImageNeedRefresh; +extern BOOLEAN HBufferImageOnlyLineNeedRefresh; +extern BOOLEAN HBufferImageMouseNeedRefresh; + +extern HEFI_EDITOR_GLOBAL_EDITOR HMainEditor; + +HEFI_EDITOR_DISK_IMAGE HDiskImage; +HEFI_EDITOR_DISK_IMAGE HDiskImageBackupVar; + +// +// for basic initialization of HDiskImage +// +HEFI_EDITOR_DISK_IMAGE HDiskImageConst = { + NULL, + 0, + 0, + 0 +}; + +/** + Initialization function for HDiskImage. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HDiskImageInit ( + VOID + ) +{ + // + // basically initialize the HDiskImage + // + CopyMem (&HDiskImage, &HDiskImageConst, sizeof (HDiskImage)); + + CopyMem (&HDiskImageBackupVar, &HDiskImageConst, sizeof (HDiskImageBackupVar)); + + return EFI_SUCCESS; +} + +/** + Backup function for HDiskImage. Only a few fields need to be backup. + This is for making the Disk buffer refresh as few as possible. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES gST->ConOut of resources. +**/ +EFI_STATUS +HDiskImageBackup ( + VOID + ) +{ + // + // backup the disk name, offset and size + // + // + SHELL_FREE_NON_NULL (HDiskImageBackupVar.Name); + + HDiskImageBackupVar.Name = CatSPrint(NULL, L"%s", HDiskImage.Name); + if (HDiskImageBackupVar.Name == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + HDiskImageBackupVar.Offset = HDiskImage.Offset; + HDiskImageBackupVar.Size = HDiskImage.Size; + + return EFI_SUCCESS; +} + +/** + Cleanup function for HDiskImage. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HDiskImageCleanup ( + VOID + ) +{ + SHELL_FREE_NON_NULL (HDiskImage.Name); + SHELL_FREE_NON_NULL (HDiskImageBackupVar.Name); + + return EFI_SUCCESS; +} + +/** + Set FileName field in HFileImage. + + @param[in] Str File name to set. + @param[in] Offset The offset. + @param[in] Size The size. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +HDiskImageSetDiskNameOffsetSize ( + IN CONST CHAR16 *Str, + IN UINTN Offset, + IN UINTN Size + ) +{ + if (Str == HDiskImage.Name) { + // + // This function might be called using HDiskImage.FileName as Str. + // Directly return without updating HDiskImage.FileName. + // + return EFI_SUCCESS; + } + + // + // free the old file name + // + SHELL_FREE_NON_NULL (HDiskImage.Name); + HDiskImage.Name = AllocateCopyPool (StrSize (Str), Str); + if (HDiskImage.Name == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + HDiskImage.Offset = Offset; + HDiskImage.Size = Size; + + return EFI_SUCCESS; +} + +/** + Read a disk from disk into HBufferImage. + + @param[in] DeviceName filename to read. + @param[in] Offset The offset. + @param[in] Size The size. + @param[in] Recover if is for recover, no information print. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occurred. + @retval EFI_INVALID_PARAMETER A parameter was invalid. +**/ +EFI_STATUS +HDiskImageRead ( + IN CONST CHAR16 *DeviceName, + IN UINTN Offset, + IN UINTN Size, + IN BOOLEAN Recover + ) +{ + CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *DupDevicePath; + EFI_DEVICE_PATH_PROTOCOL *DupDevicePathForFree; + EFI_HANDLE Handle; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + EFI_STATUS Status; + + VOID *Buffer; + CHAR16 *Str; + UINTN Bytes; + + HEFI_EDITOR_LINE *Line; + + HBufferImage.BufferType = FileTypeDiskBuffer; + + DevicePath = gEfiShellProtocol->GetDevicePathFromMap(DeviceName); + if (DevicePath == NULL) { + StatusBarSetStatusString (L"Cannot Find Device"); + return EFI_INVALID_PARAMETER; + } + DupDevicePath = DuplicateDevicePath(DevicePath); + DupDevicePathForFree = DupDevicePath; + // + // get blkio interface + // + Status = gBS->LocateDevicePath(&gEfiBlockIoProtocolGuid,&DupDevicePath,&Handle); + FreePool(DupDevicePathForFree); + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"Read Disk Failed"); + return Status; + } + Status = gBS->OpenProtocol(Handle, &gEfiBlockIoProtocolGuid, (VOID**)&BlkIo, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"Read Disk Failed"); + return Status; + } + // + // if Offset exceeds LastBlock, + // return error + // + if (Offset > BlkIo->Media->LastBlock || Offset + Size > BlkIo->Media->LastBlock) { + StatusBarSetStatusString (L"Invalid Offset + Size"); + return EFI_LOAD_ERROR; + } + + Bytes = BlkIo->Media->BlockSize * Size; + Buffer = AllocateZeroPool (Bytes); + + if (Buffer == NULL) { + StatusBarSetStatusString (L"Read Disk Failed"); + return EFI_OUT_OF_RESOURCES; + } + + // + // read from disk + // + Status = BlkIo->ReadBlocks ( + BlkIo, + BlkIo->Media->MediaId, + Offset, + Bytes, + Buffer + ); + + if (EFI_ERROR (Status)) { + FreePool (Buffer); + StatusBarSetStatusString (L"Read Disk Failed"); + return EFI_LOAD_ERROR; + } + + HBufferImageFree (); + + // + // convert buffer to line list + // + Status = HBufferImageBufferToList (Buffer, Bytes); + FreePool (Buffer); + + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"Read Disk Failed"); + return Status; + } + + Status = HDiskImageSetDiskNameOffsetSize (DeviceName, Offset, Size); + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"Read Disk Failed"); + return EFI_OUT_OF_RESOURCES; + } + // + // initialize some variables + // + HDiskImage.BlockSize = BlkIo->Media->BlockSize; + + HBufferImage.DisplayPosition.Row = 2; + HBufferImage.DisplayPosition.Column = 10; + + HBufferImage.MousePosition.Row = 2; + HBufferImage.MousePosition.Column = 10; + + HBufferImage.LowVisibleRow = 1; + HBufferImage.HighBits = TRUE; + + HBufferImage.BufferPosition.Row = 1; + HBufferImage.BufferPosition.Column = 1; + + if (!Recover) { + Str = CatSPrint(NULL, L"%d Lines Read", HBufferImage.NumLines); + if (Str == NULL) { + StatusBarSetStatusString (L"Read Disk Failed"); + return EFI_OUT_OF_RESOURCES; + } + + StatusBarSetStatusString (Str); + SHELL_FREE_NON_NULL (Str); + + HMainEditor.SelectStart = 0; + HMainEditor.SelectEnd = 0; + + } + + // + // has line + // + if (HBufferImage.Lines != NULL) { + HBufferImage.CurrentLine = CR ( + HBufferImage.ListHead->ForwardLink, + HEFI_EDITOR_LINE, + Link, + EFI_EDITOR_LINE_LIST + ); + } else { + // + // create a dummy line + // + Line = HBufferImageCreateLine (); + if (Line == NULL) { + StatusBarSetStatusString (L"Read Disk Failed"); + return EFI_OUT_OF_RESOURCES; + } + + HBufferImage.CurrentLine = Line; + } + + HBufferImage.Modified = FALSE; + HBufferImageNeedRefresh = TRUE; + HBufferImageOnlyLineNeedRefresh = FALSE; + HBufferImageMouseNeedRefresh = TRUE; + + return EFI_SUCCESS; +} + +/** + Save lines in HBufferImage to disk. + NOT ALLOW TO WRITE TO ANOTHER DISK!!!!!!!!! + + @param[in] DeviceName The device name. + @param[in] Offset The offset. + @param[in] Size The size. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occurred. + @retval EFI_INVALID_PARAMETER A parameter was invalid. +**/ +EFI_STATUS +HDiskImageSave ( + IN CHAR16 *DeviceName, + IN UINTN Offset, + IN UINTN Size + ) +{ + + CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *DupDevicePath; + EFI_DEVICE_PATH_PROTOCOL *DupDevicePathForFree; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + EFI_STATUS Status; + EFI_HANDLE Handle; + VOID *Buffer; + UINTN Bytes; + + // + // if not modified, directly return + // + if (HBufferImage.Modified == FALSE) { + return EFI_SUCCESS; + } + + HBufferImage.BufferType = FileTypeDiskBuffer; + + DevicePath = gEfiShellProtocol->GetDevicePathFromMap(DeviceName); + if (DevicePath == NULL) { +// StatusBarSetStatusString (L"Cannot Find Device"); + return EFI_INVALID_PARAMETER; + } + DupDevicePath = DuplicateDevicePath(DevicePath); + DupDevicePathForFree = DupDevicePath; + + // + // get blkio interface + // + Status = gBS->LocateDevicePath(&gEfiBlockIoProtocolGuid,&DupDevicePath,&Handle); + FreePool(DupDevicePathForFree); + if (EFI_ERROR (Status)) { +// StatusBarSetStatusString (L"Read Disk Failed"); + return Status; + } + Status = gBS->OpenProtocol(Handle, &gEfiBlockIoProtocolGuid, (VOID**)&BlkIo, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR (Status)) { +// StatusBarSetStatusString (L"Read Disk Failed"); + return Status; + } + + Bytes = BlkIo->Media->BlockSize * Size; + Buffer = AllocateZeroPool (Bytes); + + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // concatenate the line list to a buffer + // + Status = HBufferImageListToBuffer (Buffer, Bytes); + if (EFI_ERROR (Status)) { + FreePool (Buffer); + return Status; + } + + // + // write the buffer to disk + // + Status = BlkIo->WriteBlocks ( + BlkIo, + BlkIo->Media->MediaId, + Offset, + Bytes, + Buffer + ); + + FreePool (Buffer); + + if (EFI_ERROR (Status)) { + return EFI_LOAD_ERROR; + } + // + // now not modified + // + HBufferImage.Modified = FALSE; + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/DiskImage.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/DiskImage.h new file mode 100644 index 00000000..dd1f4760 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/DiskImage.h @@ -0,0 +1,89 @@ +/** @file + Defines DiskImage - the view of the file that is visible at any point, + as well as the event handlers for editing the file + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _LIB_DISK_IMAGE_H_ +#define _LIB_DISK_IMAGE_H_ + +#include "HexEditor.h" + +/** + Initialization function for HDiskImage. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HDiskImageInit ( + VOID + ); + +/** + Cleanup function for HDiskImage. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HDiskImageCleanup ( + VOID + ); + +/** + Backup function for HDiskImage. Only a few fields need to be backup. + This is for making the Disk buffer refresh as few as possible. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES gST->ConOut of resources. +**/ +EFI_STATUS +HDiskImageBackup ( + VOID + ); + +/** + Read a disk from disk into HBufferImage. + + @param[in] DeviceName filename to read. + @param[in] Offset The offset. + @param[in] Size The size. + @param[in] Recover if is for recover, no information print. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occurred. + @retval EFI_INVALID_PARAMETER A parameter was invalid. +**/ +EFI_STATUS +HDiskImageRead ( + IN CONST CHAR16 *DeviceName, + IN UINTN Offset, + IN UINTN Size, + IN BOOLEAN Recover + ); + +/** + Save lines in HBufferImage to disk. + NOT ALLOW TO WRITE TO ANOTHER DISK!!!!!!!!! + + @param[in] DeviceName The device name. + @param[in] Offset The offset. + @param[in] Size The size. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occurred. + @retval EFI_INVALID_PARAMETER A parameter was invalid. +**/ +EFI_STATUS +HDiskImageSave ( + IN CHAR16 *DeviceName, + IN UINTN Offset, + IN UINTN Size + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/FileImage.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/FileImage.c new file mode 100644 index 00000000..01fb554d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/FileImage.c @@ -0,0 +1,392 @@ +/** @file + Functions to deal with file buffer. + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "HexEditor.h" + +extern EFI_HANDLE HImageHandleBackup; +extern HEFI_EDITOR_BUFFER_IMAGE HBufferImage; + +extern BOOLEAN HBufferImageNeedRefresh; +extern BOOLEAN HBufferImageOnlyLineNeedRefresh; +extern BOOLEAN HBufferImageMouseNeedRefresh; + +extern HEFI_EDITOR_GLOBAL_EDITOR HMainEditor; + +HEFI_EDITOR_FILE_IMAGE HFileImage; +HEFI_EDITOR_FILE_IMAGE HFileImageBackupVar; + +// +// for basic initialization of HFileImage +// +HEFI_EDITOR_BUFFER_IMAGE HFileImageConst = { + NULL, + 0, + FALSE +}; + +/** + Initialization function for HFileImage + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HFileImageInit ( + VOID + ) +{ + // + // basically initialize the HFileImage + // + CopyMem (&HFileImage, &HFileImageConst, sizeof (HFileImage)); + + CopyMem ( + &HFileImageBackupVar, + &HFileImageConst, + sizeof (HFileImageBackupVar) + ); + + return EFI_SUCCESS; +} + +/** + Backup function for HFileImage. Only a few fields need to be backup. + This is for making the file buffer refresh as few as possible. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +HFileImageBackup ( + VOID + ) +{ + SHELL_FREE_NON_NULL (HFileImageBackupVar.FileName); + HFileImageBackupVar.FileName = CatSPrint(NULL, L"%s", HFileImage.FileName); + if (HFileImageBackupVar.FileName == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +/** + Cleanup function for HFileImage. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HFileImageCleanup ( + VOID + ) +{ + + SHELL_FREE_NON_NULL (HFileImage.FileName); + SHELL_FREE_NON_NULL (HFileImageBackupVar.FileName); + + return EFI_SUCCESS; +} + +/** + Set FileName field in HFileImage + + @param[in] Str File name to set. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +HFileImageSetFileName ( + IN CONST CHAR16 *Str + ) +{ + if (Str == HFileImage.FileName) { + // + // This function might be called using HFileImage.FileName as Str. + // Directly return without updating HFileImage.FileName. + // + return EFI_SUCCESS; + } + // + // free the old file name + // + SHELL_FREE_NON_NULL (HFileImage.FileName); + HFileImage.FileName = AllocateCopyPool (StrSize (Str), Str); + if (HFileImage.FileName == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +/** + Read a file from disk into HBufferImage. + + @param[in] FileName filename to read. + @param[in] Recover if is for recover, no information print. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HFileImageRead ( + IN CONST CHAR16 *FileName, + IN BOOLEAN Recover + ) +{ + HEFI_EDITOR_LINE *Line; + UINT8 *Buffer; + CHAR16 *UnicodeBuffer; + EFI_STATUS Status; + + // + // variable initialization + // + Line = NULL; + + // + // in this function, when you return error ( except EFI_OUT_OF_RESOURCES ) + // you should set status string + // since this function maybe called before the editorhandleinput loop + // so any error will cause editor return + // so if you want to print the error status + // you should set the status string + // + Status = ReadFileIntoBuffer (FileName, (VOID**)&Buffer, &HFileImage.Size, &HFileImage.ReadOnly); + // + // NULL pointer is only also a failure for a non-zero file size. + // + if ((EFI_ERROR(Status)) || (Buffer == NULL && HFileImage.Size != 0)) { + UnicodeBuffer = CatSPrint(NULL, L"Read error on file %s: %r", FileName, Status); + if (UnicodeBuffer == NULL) { + SHELL_FREE_NON_NULL(Buffer); + return EFI_OUT_OF_RESOURCES; + } + + StatusBarSetStatusString (UnicodeBuffer); + FreePool (UnicodeBuffer); + return EFI_OUT_OF_RESOURCES; + } + + HFileImageSetFileName (FileName); + + // + // free the old lines + // + HBufferImageFree (); + + Status = HBufferImageBufferToList (Buffer, HFileImage.Size); + SHELL_FREE_NON_NULL (Buffer); + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"Error parsing file."); + return Status; + } + + HBufferImage.DisplayPosition.Row = 2; + HBufferImage.DisplayPosition.Column = 10; + HBufferImage.MousePosition.Row = 2; + HBufferImage.MousePosition.Column = 10; + HBufferImage.LowVisibleRow = 1; + HBufferImage.HighBits = TRUE; + HBufferImage.BufferPosition.Row = 1; + HBufferImage.BufferPosition.Column = 1; + HBufferImage.BufferType = FileTypeFileBuffer; + + if (!Recover) { + UnicodeBuffer = CatSPrint(NULL, L"%d Lines Read", HBufferImage.NumLines); + if (UnicodeBuffer == NULL) { + SHELL_FREE_NON_NULL(Buffer); + return EFI_OUT_OF_RESOURCES; + } + + StatusBarSetStatusString (UnicodeBuffer); + FreePool (UnicodeBuffer); + + HMainEditor.SelectStart = 0; + HMainEditor.SelectEnd = 0; + } + + // + // has line + // + if (HBufferImage.Lines != 0) { + HBufferImage.CurrentLine = CR (HBufferImage.ListHead->ForwardLink, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); + } else { + // + // create a dummy line + // + Line = HBufferImageCreateLine (); + if (Line == NULL) { + SHELL_FREE_NON_NULL(Buffer); + return EFI_OUT_OF_RESOURCES; + } + + HBufferImage.CurrentLine = Line; + } + + HBufferImage.Modified = FALSE; + HBufferImageNeedRefresh = TRUE; + HBufferImageOnlyLineNeedRefresh = FALSE; + HBufferImageMouseNeedRefresh = TRUE; + + return EFI_SUCCESS; +} + +/** + Save lines in HBufferImage to disk. + + @param[in] FileName The file name. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HFileImageSave ( + IN CHAR16 *FileName + ) +{ + + LIST_ENTRY *Link; + HEFI_EDITOR_LINE *Line; + CHAR16 *Str; + EFI_STATUS Status; + UINTN NumLines; + SHELL_FILE_HANDLE FileHandle; + UINTN TotalSize; + UINT8 *Buffer; + UINT8 *Ptr; + EDIT_FILE_TYPE BufferTypeBackup; + + BufferTypeBackup = HBufferImage.BufferType; + HBufferImage.BufferType = FileTypeFileBuffer; + + // + // if is the old file + // + if (HFileImage.FileName != NULL && FileName != NULL && StrCmp (FileName, HFileImage.FileName) == 0) { + // + // check whether file exists on disk + // + if (ShellIsFile(FileName) == EFI_SUCCESS) { + // + // current file exists on disk + // so if not modified, then not save + // + if (HBufferImage.Modified == FALSE) { + return EFI_SUCCESS; + } + // + // if file is read-only, set error + // + if (HFileImage.ReadOnly == TRUE) { + StatusBarSetStatusString (L"Read Only File Can Not Be Saved"); + return EFI_SUCCESS; + } + } + } + + if (ShellIsDirectory(FileName) == EFI_SUCCESS) { + StatusBarSetStatusString (L"Directory Can Not Be Saved"); + return EFI_LOAD_ERROR; + } + + Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0); + + if (!EFI_ERROR (Status)) { + // + // the file exits, delete it + // + Status = ShellDeleteFile (&FileHandle); + if (EFI_ERROR (Status) || Status == EFI_WARN_DELETE_FAILURE) { + StatusBarSetStatusString (L"Write File Failed"); + return EFI_LOAD_ERROR; + } + } + + // + // write all the lines back to disk + // + NumLines = 0; + TotalSize = 0; + for (Link = HBufferImage.ListHead->ForwardLink; Link != HBufferImage.ListHead; Link = Link->ForwardLink) { + Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); + + if (Line->Size != 0) { + TotalSize += Line->Size; + } + // + // end of if Line -> Size != 0 + // + NumLines++; + } + // + // end of for Link + // + Buffer = AllocateZeroPool (TotalSize); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Ptr = Buffer; + for (Link = HBufferImage.ListHead->ForwardLink; Link != HBufferImage.ListHead; Link = Link->ForwardLink) { + Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); + + if (Line->Size != 0) { + CopyMem (Ptr, Line->Buffer, Line->Size); + Ptr += Line->Size; + } + // + // end of if Line -> Size != 0 + // + } + + + Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0); + + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"Create File Failed"); + return EFI_LOAD_ERROR; + } + + Status = ShellWriteFile (FileHandle, &TotalSize, Buffer); + FreePool (Buffer); + if (EFI_ERROR (Status)) { + ShellDeleteFile (&FileHandle); + return EFI_LOAD_ERROR; + } + + ShellCloseFile(&FileHandle); + + HBufferImage.Modified = FALSE; + + // + // set status string + // + Str = CatSPrint(NULL, L"%d Lines Written", NumLines); + StatusBarSetStatusString (Str); + FreePool (Str); + + // + // now everything is ready , you can set the new file name to filebuffer + // + if ((BufferTypeBackup != FileTypeFileBuffer && FileName != NULL) || + (FileName != NULL && HFileImage.FileName != NULL && StringNoCaseCompare (&FileName, &HFileImage.FileName) != 0)){ + // + // not the same + // + HFileImageSetFileName (FileName); + if (HFileImage.FileName == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + HFileImage.ReadOnly = FALSE; + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/FileImage.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/FileImage.h new file mode 100644 index 00000000..9472b343 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/FileImage.h @@ -0,0 +1,77 @@ +/** @file + Defines FileImage - the view of the file that is visible at any point, + as well as the event handlers for editing the file + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _LIB_FILE_IMAGE_H_ +#define _LIB_FILE_IMAGE_H_ + +#include "HexEditor.h" + +/** + Initialization function for HFileImage + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HFileImageInit ( + VOID + ); + +/** + Cleanup function for HFileImage. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HFileImageCleanup ( + VOID + ); + +/** + Backup function for HFileImage. Only a few fields need to be backup. + This is for making the file buffer refresh as few as possible. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +HFileImageBackup ( + VOID + ); + +/** + Read a file from disk into HBufferImage. + + @param[in] FileName filename to read. + @param[in] Recover if is for recover, no information print. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HFileImageRead ( + IN CONST CHAR16 *FileName, + IN BOOLEAN Recover + ); + +/** + Save lines in HBufferImage to disk. + + @param[in] FileName The file name. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HFileImageSave ( + IN CHAR16 *FileName + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexEdit.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexEdit.c new file mode 100644 index 00000000..ac1bc22b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexEdit.c @@ -0,0 +1,271 @@ +/** @file + Main entry point of editor + + (C) Copyright 2014-2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDebug1CommandsLib.h" +#include "HexEditor.h" + +// +// Global Variables +// +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-f", TypeFlag}, + {L"-d", TypeFlag}, + {L"-m", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'hexedit' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunHexEdit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + CHAR16 *Buffer; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + LIST_ENTRY *Package; + CHAR16 *NewName; + CONST CHAR16 *Name; + UINTN Offset; + UINTN Size; + EDIT_FILE_TYPE WhatToDo; + + Buffer = NULL; + ShellStatus = SHELL_SUCCESS; + NewName = NULL; + Buffer = NULL; + Name = NULL; + Offset = 0; + Size = 0; + WhatToDo = FileTypeNone; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"hexedit", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // Check for -d + // + if (ShellCommandLineGetFlag(Package, L"-d")){ + if (ShellCommandLineGetCount(Package) < 4) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"hexedit"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetCount(Package) > 4) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"hexedit"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + WhatToDo = FileTypeDiskBuffer; + Name = ShellCommandLineGetRawValue(Package, 1); + Offset = ShellStrToUintn(ShellCommandLineGetRawValue(Package, 2)); + Size = ShellStrToUintn(ShellCommandLineGetRawValue(Package, 3)); + } + if (Offset == (UINTN)-1 || Size == (UINTN)-1) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDebug1HiiHandle, L"hexedit", L"-d"); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } + + // + // check for -f + // + if (ShellCommandLineGetFlag(Package, L"-f") && (WhatToDo == FileTypeNone)){ + if (ShellCommandLineGetCount(Package) < 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"hexedit"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetCount(Package) > 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"hexedit"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Name = ShellCommandLineGetRawValue(Package, 1); + if (Name == NULL || !IsValidFileName(Name)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"hexedit", Name); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + WhatToDo = FileTypeFileBuffer; + } + } + } + + // + // check for -m + // + if (ShellCommandLineGetFlag(Package, L"-m") && (WhatToDo == FileTypeNone)){ + if (ShellCommandLineGetCount(Package) < 3) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"hexedit"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetCount(Package) > 3) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"hexedit"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + WhatToDo = FileTypeMemBuffer; + Offset = ShellStrToUintn(ShellCommandLineGetRawValue(Package, 1)); + Size = ShellStrToUintn(ShellCommandLineGetRawValue(Package, 2)); + } + } + Name = ShellCommandLineGetRawValue(Package, 1); + if (WhatToDo == FileTypeNone && Name != NULL) { + if (ShellCommandLineGetCount(Package) > 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"hexedit"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (!IsValidFileName(Name)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"hexedit", Name); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + WhatToDo = FileTypeFileBuffer; + } + } else if (WhatToDo == FileTypeNone) { + if (gEfiShellProtocol->GetCurDir(NULL) == NULL) { + ShellStatus = SHELL_NOT_FOUND; + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellDebug1HiiHandle, L"hexedit"); + } else { + NewName = EditGetDefaultFileName(L"bin"); + Name = NewName; + WhatToDo = FileTypeFileBuffer; + } + } + + if (ShellStatus == SHELL_SUCCESS && WhatToDo == FileTypeNone) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"hexedit"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (WhatToDo == FileTypeFileBuffer && ShellGetCurrentDir(NULL) == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellDebug1HiiHandle, L"hexedit"); + ShellStatus = SHELL_INVALID_PARAMETER; + } + + if (ShellStatus == SHELL_SUCCESS) { + // + // Do the editor + // + Status = HMainEditorInit (); + if (EFI_ERROR (Status)) { + gST->ConOut->ClearScreen (gST->ConOut); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_INIT_FAILED), gShellDebug1HiiHandle); + } else { + HMainEditorBackup (); + switch (WhatToDo) { + case FileTypeFileBuffer: + Status = HBufferImageRead ( + Name==NULL?L"":Name, + NULL, + 0, + 0, + 0, + 0, + FileTypeFileBuffer, + FALSE + ); + break; + + case FileTypeDiskBuffer: + Status = HBufferImageRead ( + NULL, + Name==NULL?L"":Name, + Offset, + Size, + 0, + 0, + FileTypeDiskBuffer, + FALSE + ); + break; + + case FileTypeMemBuffer: + Status = HBufferImageRead ( + NULL, + NULL, + 0, + 0, + (UINT32) Offset, + Size, + FileTypeMemBuffer, + FALSE + ); + break; + + default: + Status = EFI_NOT_FOUND; + break; + } + if (!EFI_ERROR (Status)) { + HMainEditorRefresh (); + Status = HMainEditorKeyInput (); + } + if (Status != EFI_OUT_OF_RESOURCES) { + // + // back up the status string + // + Buffer = CatSPrint (NULL, L"%s\r\n", StatusBarGetString()); + } + } + + // + // cleanup + // + HMainEditorCleanup (); + + if (EFI_ERROR (Status)) { + if (ShellStatus == SHELL_SUCCESS) { + ShellStatus = SHELL_UNSUPPORTED; + } + } + + // + // print editor exit code on screen + // + if (Status == EFI_OUT_OF_RESOURCES) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellDebug1HiiHandle, L"hexedit"); + } else if (EFI_ERROR(Status)){ + if (Buffer != NULL) { + if (StrCmp (Buffer, L"") != 0) { + // + // print out the status string + // + ShellPrintEx(-1, -1, L"%s", Buffer); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_UNKNOWN_EDITOR), gShellDebug1HiiHandle); + } + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_UNKNOWN_EDITOR), gShellDebug1HiiHandle); + } + } + } + ShellCommandLineFreeVarList (Package); + } + + SHELL_FREE_NON_NULL (Buffer); + SHELL_FREE_NON_NULL (NewName); + return ShellStatus; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexEditor.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexEditor.h new file mode 100644 index 00000000..e68937ea --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexEditor.h @@ -0,0 +1,35 @@ +/** @file + Main include file for hex editor + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_SHELL_HEXEDIT_H_ +#define _EFI_SHELL_HEXEDIT_H_ + +#include "UefiShellDebug1CommandsLib.h" +#include "HexEditorTypes.h" + +#include "MainHexEditor.h" + +#include "BufferImage.h" +#include "FileImage.h" +#include "DiskImage.h" +#include "MemImage.h" + +#include "EditTitleBar.h" +#include "EditStatusBar.h" +#include "EditInputBar.h" +#include "EditMenuBar.h" + +#include "Misc.h" + +#include "Clipboard.h" + +extern HEFI_EDITOR_GLOBAL_EDITOR HMainEditor; +extern BOOLEAN HEditorFirst; +extern BOOLEAN HEditorExit; + +#endif // _HEDITOR_H diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexEditorTypes.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexEditorTypes.h new file mode 100644 index 00000000..3ac8432b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexEditorTypes.h @@ -0,0 +1,120 @@ +/** @file + data types that are used by editor + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _HEDITOR_TYPE_H_ +#define _HEDITOR_TYPE_H_ + +#include "UefiShellDebug1CommandsLib.h" +#include "EditTitleBar.h" + +#define EFI_EDITOR_LINE_LIST SIGNATURE_32 ('e', 'e', 'l', 'l') + +#define ASCII_POSITION ((0x10 * 3) + 12) + + +typedef struct { + UINTN Row; + UINTN Column; +} HEFI_EDITOR_POSITION; + +typedef +EFI_STATUS +(*HEFI_MENU_ITEM_FUNCTION) ( + VOID + ); + +typedef struct { + CHAR16 Name[50]; + CHAR16 Key[3]; + HEFI_MENU_ITEM_FUNCTION Function; +} HMENU_ITEMS; + +typedef struct _HEFI_EDITOR_LINE { + UINTN Signature; + UINT8 Buffer[0x10]; + UINTN Size; // unit is Unicode + LIST_ENTRY Link; +} HEFI_EDITOR_LINE; + +typedef struct _HEFI_EDITOR_MENU_ITEM { + CHAR16 NameToken; + CHAR16 FunctionKeyToken; + HEFI_MENU_ITEM_FUNCTION Function; +} HEFI_EDITOR_MENU_ITEM; + +typedef struct { + UINT32 Foreground : 4; + UINT32 Background : 4; +} HEFI_EDITOR_COLOR_ATTRIBUTES; + +typedef union { + HEFI_EDITOR_COLOR_ATTRIBUTES Colors; + UINTN Data; +} HEFI_EDITOR_COLOR_UNION; + +typedef struct { + UINTN Columns; + UINTN Rows; +} HEFI_EDITOR_TEXT_MODE; + + +typedef struct { + CHAR16 *Name; + + UINTN BlockSize; + UINTN Size; + UINTN Offset; +} HEFI_EDITOR_DISK_IMAGE; + +typedef struct { + EFI_CPU_IO2_PROTOCOL *IoFncs; + UINTN Offset; + UINTN Size; +} HEFI_EDITOR_MEM_IMAGE; + +typedef struct { + CHAR16 *FileName; + UINTN Size; // file size + BOOLEAN ReadOnly; // file is read-only or not +} HEFI_EDITOR_FILE_IMAGE; + +typedef struct { + LIST_ENTRY *ListHead; // list head of lines + HEFI_EDITOR_LINE *Lines; // lines of current file + UINTN NumLines; // number of lines + HEFI_EDITOR_LINE *CurrentLine; // current line cursor is at + HEFI_EDITOR_POSITION DisplayPosition; // cursor position in screen + HEFI_EDITOR_POSITION MousePosition; // mouse position in screen + HEFI_EDITOR_POSITION BufferPosition; // cursor position in buffer + UINTN LowVisibleRow; // the lowest visible row of file position + BOOLEAN HighBits; // cursor is at the high4 bits or low4 bits + BOOLEAN Modified; // BUFFER is modified or not + EDIT_FILE_TYPE BufferType; + + HEFI_EDITOR_FILE_IMAGE *FileImage; + HEFI_EDITOR_DISK_IMAGE *DiskImage; + HEFI_EDITOR_MEM_IMAGE *MemImage; + +} HEFI_EDITOR_BUFFER_IMAGE; + +typedef struct { + HEFI_EDITOR_BUFFER_IMAGE *BufferImage; + + HEFI_EDITOR_COLOR_UNION ColorAttributes; + HEFI_EDITOR_POSITION ScreenSize; // row number and column number + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInputEx; + BOOLEAN MouseSupported; + EFI_SIMPLE_POINTER_PROTOCOL *MouseInterface; + INT32 MouseAccumulatorX; + INT32 MouseAccumulatorY; + + UINTN SelectStart; // starting from 1 + UINTN SelectEnd; // starting from 1 +} HEFI_EDITOR_GLOBAL_EDITOR; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexeditStrings.uni b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexeditStrings.uni new file mode 100644 index 00000000..65d342fb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexeditStrings.uni @@ -0,0 +1,70 @@ +// /** +// +// Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+// (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// Abstract: +// +// Additional string definitions for UEFI Shell 2.0 Debug1 profile Edit command +// +// +// **/ + +/=# + +#langdef en-US "english" + + +#string STR_HEXEDIT_USAGE #language en-US "\n\n %EHexEditor Usage%N\n" +#string STR_HEXEDIT_FILENAME #language en-US " %H[-f] Filename%N Open File For Editing\n" +#string STR_HEXEDIT_DISKNAME #language en-US " %H-d DiskName FirstBlockNo. BlockNumber%N Open Disk Block For Editing\n" +#string STR_HEXEDIT_OFFSET_SIZE #language en-US " %H-m Offset Size%N Open Memory Region For Editing\n" +#string STR_HEXEDIT_FILE_NAME #language en-US "%Hhexedit%N: Invalid File Name\n" +#string STR_HEXEDIT_LIBEDITOR_MAINEDITOR_TITLE #language en-US "%EMainEditor init failed on TitleBar init\n%N" +#string STR_HEXEDIT_LIBEDITOR_MAINEDITOR_MAINMENU #language en-US "%EMainEditor init failed on MainMenu init\n%N" +#string STR_HEXEDIT_LIBEDITOR_MAINEDITOR_STATUS #language en-US "%EMainEditor init failed on StatusBar init\n%N" +#string STR_HEXEDIT_LIBEDITOR_MAINEDITOR_INPUTBAR #language en-US "%EMainEditor init failed on InputBar init\n%N" +#string STR_HEXEDIT_LIBEDITOR_MAINEDITOR_BUFFERIMAGE #language en-US "%EMainEditor init failed on BufferImage init\n%N" +#string STR_HEXEDIT_LIBEDITOR_MAINEDITOR_CLIPBOARD #language en-US "%EMainEditor init failed on ClipBoard init\n%N" +#string STR_HEXEDIT_LIBEDITOR_TITLEBAR_CLEAN #language en-US "TitleBar cleanup failed\n" +#string STR_HEXEDIT_LIBEDITOR_MENUBAR_CLEAN #language en-US "MenuBar cleanup failed\n" +#string STR_HEXEDIT_LIBEDITOR_STATUSBAR_CLEAN #language en-US "StatusBar cleanup failed\n" +#string STR_HEXEDIT_LIBEDITOR_INPUTBAR_CLEAN #language en-US "InputBar cleanup failed\n" +#string STR_HEXEDIT_LIBEDITOR_BUFFERIMAGE_CLEAN #language en-US "BufferImage cleanup failed\n" +#string STR_HEXEDIT_LIBEDITOR_CLIPBOARD_CLEAN #language en-US "ClipBoard cleanup failed\n" +#string STR_HEXEDIT_LIBINPUTBAR_MAININPUTBAR #language en-US "%s" +#string STR_HEXEDIT_LIBMENUBAR_OPEN_FILE #language en-US "Open File" +#string STR_HEXEDIT_LIBMENUBAR_OPEN_DISK #language en-US "Open Disk" +#string STR_HEXEDIT_LIBMENUBAR_OPEN_MEMORY #language en-US "Open Memory" +#string STR_HEXEDIT_LIBMENUBAR_SAVE_BUFFER #language en-US "Save Buffer" +#string STR_HEXEDIT_LIBMENUBAR_SELECT_START #language en-US "Select Start" +#string STR_HEXEDIT_LIBMENUBAR_SELECT_END #language en-US "Select End" +#string STR_HEXEDIT_LIBMENUBAR_CUT #language en-US "Cut" +#string STR_HEXEDIT_LIBMENUBAR_PASTE #language en-US "Paste" +#string STR_HEXEDIT_LIBMENUBAR_GO_TO_OFFSET #language en-US "Go To Offset" +#string STR_HEXEDIT_LIBTITLEBAR_MAINEDITOR #language en-US "%s" +#string STR_HEXEDIT_LIBTITLEBAR_MAINEDITOR_C #language en-US "%c" +#string STR_HEXEDIT_LIBTITLEBAR_MAINEDITOR_TWOVARS #language en-US "( %X ~ %X ) " +#string STR_HEXEDIT_LIBTITLEBAR_FILE #language en-US " [FILE]" +#string STR_HEXEDIT_LIBTITLEBAR_DISK #language en-US " [DISK]" +#string STR_HEXEDIT_LIBTITLEBAR_MEM #language en-US " [MEM]" +#string STR_HEXEDIT_HELP_TITLE #language en-US "Help \n" +#string STR_HEXEDIT_HELP_BLANK #language en-US " \n" +#string STR_HEXEDIT_HELP_LIST_TITLE #language en-US "Control Key Function Key Command \n" +#string STR_HEXEDIT_HELP_DIV #language en-US "----------- ------------ ----------------- \n" +#string STR_HEXEDIT_HELP_GO_TO_OFFSET #language en-US "Ctrl-G F1 Go To Offset \n" +#string STR_HEXEDIT_HELP_SAVE_BUFFER #language en-US "Ctrl-S F2 Save Buffer \n" +#string STR_HEXEDIT_HELP_EXIT #language en-US "Ctrl-Q F3 Exit \n" +#string STR_HEXEDIT_HELP_SELECT_START #language en-US "Ctrl-T F4 Select Start \n" +#string STR_HEXEDIT_HELP_SELECT_END #language en-US "Ctrl-D F5 Select End \n" +#string STR_HEXEDIT_HELP_CUT #language en-US "Ctrl-X F6 Cut \n" +#string STR_HEXEDIT_HELP_PASTE #language en-US "Ctrl-V F7 Paste \n" +#string STR_HEXEDIT_HELP_OPEN_FILE #language en-US "Ctrl-O F8 Open File \n" +#string STR_HEXEDIT_HELP_OPEN_DISK #language en-US "Ctrl-I F9 Open Disk \n" +#string STR_HEXEDIT_HELP_OPEN_MEMORY #language en-US "Ctrl-M F10 Open Memory \n" +#string STR_HEXEDIT_HELP_EXIT_HELP #language en-US "Use Ctrl-W to exit this help \n" +#string STR_HEXEDIT_INIT_FAILED #language en-US "%Hhexedit%N: Initialization failed\n" +#string STR_HEXEDIT_ONE_VAR #language en-US "%Hhexedit%N: %s\n" +#string STR_HEXEDIT_UNKNOWN_EDITOR #language en-US "%Hhexedit%N: Unknown editor error\n" +#string STR_HEXEDIT_NOREDIRECT #language en-US "%Hhexedit%N: Redirection is not allowed\n" diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MainHexEditor.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MainHexEditor.c new file mode 100644 index 00000000..43e99ba3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MainHexEditor.c @@ -0,0 +1,2372 @@ +/** @file + Defines the Main Editor data type - + - Global variables + - Instances of the other objects of the editor + - Main Interfaces + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "HexEditor.h" +#include "EditStatusBar.h" +#include "EditInputBar.h" + +HEFI_EDITOR_COLOR_ATTRIBUTES HOriginalColors; +INTN HOriginalMode; + +// +// the first time editor launch +// +BOOLEAN HEditorFirst; + +// +// it's time editor should exit +// +BOOLEAN HEditorExit; + +BOOLEAN HEditorMouseAction; + +extern HEFI_EDITOR_BUFFER_IMAGE HBufferImage; +extern HEFI_EDITOR_BUFFER_IMAGE HBufferImageBackupVar; + +extern BOOLEAN HBufferImageMouseNeedRefresh; +extern BOOLEAN HBufferImageNeedRefresh; +extern BOOLEAN HBufferImageOnlyLineNeedRefresh; + +HEFI_EDITOR_GLOBAL_EDITOR HMainEditor; +HEFI_EDITOR_GLOBAL_EDITOR HMainEditorBackupVar; + +// +// basic initialization for MainEditor +// +HEFI_EDITOR_GLOBAL_EDITOR HMainEditorConst = { + &HBufferImage, + { + {0, 0} + }, + { + 0, + 0 + }, + NULL, + FALSE, + NULL, + 0, + 0, + 1, + 1 +}; + +/** + Help info that will be displayed. +**/ +EFI_STRING_ID HexMainMenuHelpInfo[] = { + STRING_TOKEN(STR_HEXEDIT_HELP_TITLE), + STRING_TOKEN(STR_HEXEDIT_HELP_BLANK), + STRING_TOKEN(STR_HEXEDIT_HELP_LIST_TITLE), + STRING_TOKEN(STR_HEXEDIT_HELP_DIV), + STRING_TOKEN(STR_HEXEDIT_HELP_GO_TO_OFFSET), + STRING_TOKEN(STR_HEXEDIT_HELP_SAVE_BUFFER), + STRING_TOKEN(STR_HEXEDIT_HELP_EXIT), + STRING_TOKEN(STR_HEXEDIT_HELP_SELECT_START), + STRING_TOKEN(STR_HEXEDIT_HELP_SELECT_END), + STRING_TOKEN(STR_HEXEDIT_HELP_CUT), + STRING_TOKEN(STR_HEXEDIT_HELP_PASTE), + STRING_TOKEN(STR_HEXEDIT_HELP_OPEN_FILE), + STRING_TOKEN(STR_HEXEDIT_HELP_OPEN_DISK), + STRING_TOKEN(STR_HEXEDIT_HELP_OPEN_MEMORY), + STRING_TOKEN(STR_HEXEDIT_HELP_BLANK), + STRING_TOKEN(STR_HEXEDIT_HELP_EXIT_HELP), + STRING_TOKEN(STR_HEXEDIT_HELP_BLANK), + STRING_TOKEN(STR_HEXEDIT_HELP_BLANK), + STRING_TOKEN(STR_HEXEDIT_HELP_BLANK), + STRING_TOKEN(STR_HEXEDIT_HELP_BLANK), + STRING_TOKEN(STR_HEXEDIT_HELP_BLANK), + STRING_TOKEN(STR_HEXEDIT_HELP_BLANK), + STRING_TOKEN(STR_HEXEDIT_HELP_DIV), + 0 +}; + + +/** + show help menu. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HMainCommandDisplayHelp ( + VOID + ) +{ + INT32 CurrentLine; + CHAR16 *InfoString; + EFI_KEY_DATA KeyData; + EFI_STATUS Status; + UINTN EventIndex; + + // + // print helpInfo + // + for (CurrentLine = 0; 0 != HexMainMenuHelpInfo[CurrentLine]; CurrentLine++) { + InfoString = HiiGetString(gShellDebug1HiiHandle, HexMainMenuHelpInfo[CurrentLine] +, NULL); + ShellPrintEx (0,CurrentLine+1,L"%E%s%N",InfoString); + } + + // + // scan for ctrl+w + // + while (TRUE) { + Status = gBS->WaitForEvent (1, &HMainEditor.TextInputEx->WaitForKeyEx, &EventIndex); + if (EFI_ERROR (Status) || (EventIndex != 0)) { + continue; + } + Status = HMainEditor.TextInputEx->ReadKeyStrokeEx (HMainEditor.TextInputEx, &KeyData); + if (EFI_ERROR (Status)) { + continue; + } + + if (((KeyData.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) == 0) || + (KeyData.KeyState.KeyShiftState == EFI_SHIFT_STATE_VALID)) { + // + // For consoles that don't support/report shift state, + // CTRL+W is translated to L'W' - L'A' + 1. + // + if (KeyData.Key.UnicodeChar == L'W' - L'A' + 1) { + break; + } + } else if (((KeyData.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) && + ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) && + ((KeyData.KeyState.KeyShiftState & ~(EFI_SHIFT_STATE_VALID | EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) == 0)) { + // + // For consoles that supports/reports shift state, + // make sure that only CONTROL shift key is pressed. + // + if ((KeyData.Key.UnicodeChar == 'w') || (KeyData.Key.UnicodeChar == 'W')) { + break; + } + } + } + + // update screen with buffer's info + HBufferImageNeedRefresh = TRUE; + HBufferImageOnlyLineNeedRefresh = FALSE; + HBufferImageRefresh (); + + return EFI_SUCCESS; +} + +/** + Move cursor to specified lines. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HMainCommandGoToOffset ( + VOID + ) +{ + UINTN Size; + UINT64 Offset; + EFI_STATUS Status; + UINTN FRow; + UINTN FCol; + + // + // variable initialization + // + Size = 0; + Offset = 0; + FRow = 0; + FCol = 0; + + // + // get offset + // + Status = InputBarSetPrompt (L"Go To Offset: "); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarSetStringSize (8); + if (EFI_ERROR (Status)) { + return Status; + } + + while (1) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + + return EFI_SUCCESS; + } + // + // THE input string length should > 0 + // + if (StrLen (InputBarGetString()) > 0) { + Status = ShellConvertStringToUint64 (InputBarGetString(), &Offset, TRUE, FALSE); + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"Invalid Offset"); + return EFI_SUCCESS; + } + + break; + } + } + + Size = HBufferImageGetTotalSize (); + if (Offset >= Size) { + StatusBarSetStatusString (L"Invalid Offset"); + return EFI_SUCCESS; + } + + FRow = (UINTN)DivU64x32(Offset , 0x10) + 1; + FCol = (UINTN)ModU64x32(Offset , 0x10) + 1; + + HBufferImageMovePosition (FRow, FCol, TRUE); + + HBufferImageNeedRefresh = TRUE; + HBufferImageOnlyLineNeedRefresh = FALSE; + HBufferImageMouseNeedRefresh = TRUE; + + return EFI_SUCCESS; +} + +/** + Save current opened buffer. + If is file buffer, you can save to current file name or + save to another file name. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation occurred. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HMainCommandSaveBuffer ( + VOID + ) +{ + EFI_STATUS Status; + BOOLEAN Done; + CHAR16 *FileName; + BOOLEAN OldFile; + CHAR16 *Str; + EFI_FILE_INFO *Info; + SHELL_FILE_HANDLE ShellFileHandle; + + if (HMainEditor.BufferImage->BufferType != FileTypeFileBuffer) { + if (!HMainEditor.BufferImage->Modified) { + return EFI_SUCCESS; + } + + Status = InputBarSetPrompt (L"Dangerous to save disk/mem buffer. Save (Yes/No/Cancel) ? "); + if (EFI_ERROR (Status)) { + return Status; + } + // + // the answer is just one character + // + Status = InputBarSetStringSize (1); + if (EFI_ERROR (Status)) { + return Status; + } + // + // loop for user's answer + // valid answer is just 'y' 'Y', 'n' 'N', 'c' 'C' + // + while (1) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + + switch (InputBarGetString()[0]) { + case L'y': + case L'Y': + // + // want to save this buffer first + // + Status = HBufferImageSave ( + NULL, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + HMainEditor.BufferImage->BufferType + ); + + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"BufferSave: Problems Writing"); + return Status; + } + + return EFI_SUCCESS; + + case L'n': + case L'N': + // + // the file won't be saved + // + return EFI_SUCCESS; + + case L'c': + case L'C': + return EFI_SUCCESS; + } + // + // end of switch + // + } + // + // ENDOF WHILE + // + } + // + // ENDOF != FILEBUFFER + // + // This command will save currently opened file to disk. + // You can choose save to another file name or just save to + // current file name. + // Below is the scenario of Save File command: ( + // Suppose the old file name is A ) + // 1. An Input Bar will be prompted: "File To Save: [ old file name]" + // IF user press ESC, Save File command ends . + // IF user press Enter, input file name will be A. + // IF user inputs a new file name B, input file name will be B. + // + // 2. IF input file name is A, go to do Step 3. + // IF input file name is B, go to do Step 4. + // + // 3. IF A is read only, Status Bar will show "Access Denied" + // and Save File commands ends. + // IF A is not read only, save file buffer to disk + // and remove Modified flag in Title Bar , then Save File command ends. + // + // 4. IF B does not exist, create this file and save file buffer to it. + // Go to do Step 7. + // IF B exits, do Step 5. + // + // 5. An Input Bar will be prompted: + // "File Exists. Overwrite ( Yes/No/Cancel ) ?" + // IF user press 'y' or 'Y', do Step 6. + // IF user press 'n' or 'N', Save File commands ends. + // IF user press 'c' or 'C' or ESC, Save File commands ends. + // + // 6. IF B is a read-only file, Status Bar will show "Access Denied" + // and Save File commands ends. + // IF B can be read and write, save file buffer to B. + // + // 7. Update File Name field in Title Bar to B + // and remove the Modified flag in Title Bar. + // + Str = CatSPrint(NULL, + L"File to Save: [%s]", + HMainEditor.BufferImage->FileImage->FileName + ); + if (Str == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (StrLen (Str) >= 50) { + // + // replace the long file name with "..." + // + Str[46] = L'.'; + Str[47] = L'.'; + Str[48] = L'.'; + Str[49] = L']'; + Str[50] = L'\0'; + } + + Status = InputBarSetPrompt (Str); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarSetStringSize (100); + if (EFI_ERROR (Status)) { + return Status; + } + // + // get new file name + // + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // if user pressed ESC + // + if (Status == EFI_NOT_READY) { + SHELL_FREE_NON_NULL (Str); + return EFI_SUCCESS; + } + + SHELL_FREE_NON_NULL (Str); + + // + // if just enter pressed, so think save to current file name + // + if (StrLen (InputBarGetString()) == 0) { + FileName = CatSPrint(NULL, + L"%s", + HMainEditor.BufferImage->FileImage->FileName + ); + } else { + FileName = CatSPrint(NULL, L"%s", InputBarGetString()); + } + + if (FileName == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (!IsValidFileName (FileName)) { + StatusBarSetStatusString (L"Invalid File Name"); + SHELL_FREE_NON_NULL (FileName); + return EFI_SUCCESS; + } + + OldFile = FALSE; + + // + // save to the old file + // + if (StringNoCaseCompare ( + &FileName, + &HMainEditor.BufferImage->FileImage->FileName + ) == 0) { + OldFile = TRUE; + } + + if (OldFile) { + // + // if the file is read only, so can not write back to it. + // + if (HMainEditor.BufferImage->FileImage->ReadOnly) { + StatusBarSetStatusString (L"Access Denied"); + SHELL_FREE_NON_NULL (FileName); + return EFI_SUCCESS; + } + } else { + Status = ShellOpenFileByName (FileName, &ShellFileHandle, EFI_FILE_MODE_READ, 0); + + if (!EFI_ERROR (Status)) { + + Info = ShellGetFileInfo(ShellFileHandle); + + ShellCloseFile(&ShellFileHandle); + // + // check if read only + // + if (Info->Attribute & EFI_FILE_READ_ONLY) { + StatusBarSetStatusString (L"Access Denied"); + SHELL_FREE_NON_NULL (FileName); + return EFI_SUCCESS; + } + + SHELL_FREE_NON_NULL(Info); + // + // ask user whether to overwrite this file + // + Status = InputBarSetPrompt (L"File exists. Overwrite (Yes/No/Cancel) ? "); + if (EFI_ERROR (Status)) { + SHELL_FREE_NON_NULL (FileName); + return Status; + } + + Status = InputBarSetStringSize (1); + if (EFI_ERROR (Status)) { + SHELL_FREE_NON_NULL (FileName); + return Status; + } + + Done = FALSE; + while (!Done) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + if (Status == EFI_NOT_READY) { + SHELL_FREE_NON_NULL (FileName); + return EFI_SUCCESS; + } + + switch (InputBarGetString()[0]) { + case L'y': + case L'Y': + Done = TRUE; + break; + case L'n': + case L'N': + SHELL_FREE_NON_NULL (FileName); + return EFI_SUCCESS; + case L'c': + case L'C': + SHELL_FREE_NON_NULL (FileName); + return EFI_SUCCESS; + } // switch + } // while + } // if opened existing file + } // if OldFile + + // + // save file back to disk + // + Status = HBufferImageSave ( + FileName, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + FileTypeFileBuffer + ); + SHELL_FREE_NON_NULL (FileName); + + if (EFI_ERROR (Status)) { + return EFI_LOAD_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Load a disk buffer editor. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation occurred. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HMainCommandSelectStart ( + VOID + ) +{ + UINTN Start; + + Start = (HMainEditor.BufferImage->BufferPosition.Row - 1) * 0x10 + HMainEditor.BufferImage->BufferPosition.Column; + + // + // last line + // + if (HMainEditor.BufferImage->CurrentLine->Link.ForwardLink == HMainEditor.BufferImage->ListHead) { + if (HMainEditor.BufferImage->BufferPosition.Column > HMainEditor.BufferImage->CurrentLine->Size) { + StatusBarSetStatusString (L"Invalid Block Start"); + return EFI_LOAD_ERROR; + } + } + + if (HMainEditor.SelectEnd != 0 && Start > HMainEditor.SelectEnd) { + StatusBarSetStatusString (L"Invalid Block Start"); + return EFI_LOAD_ERROR; + } + + HMainEditor.SelectStart = Start; + + HBufferImageNeedRefresh = TRUE; + + return EFI_SUCCESS; +} + +/** + Load a disk buffer editor. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation occurred. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HMainCommandSelectEnd ( + VOID + ) +{ + UINTN End; + + End = (HMainEditor.BufferImage->BufferPosition.Row - 1) * 0x10 + HMainEditor.BufferImage->BufferPosition.Column; + + // + // last line + // + if (HMainEditor.BufferImage->CurrentLine->Link.ForwardLink == HMainEditor.BufferImage->ListHead) { + if (HMainEditor.BufferImage->BufferPosition.Column > HMainEditor.BufferImage->CurrentLine->Size) { + StatusBarSetStatusString (L"Invalid Block End"); + return EFI_LOAD_ERROR; + } + } + + if (HMainEditor.SelectStart != 0 && End < HMainEditor.SelectStart) { + StatusBarSetStatusString (L"Invalid Block End"); + return EFI_SUCCESS; + } + + HMainEditor.SelectEnd = End; + + HBufferImageNeedRefresh = TRUE; + + return EFI_SUCCESS; +} + +/** + Cut current line to clipboard. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation occurred. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HMainCommandCut ( + VOID + ) +{ + UINTN Index; + LIST_ENTRY *Link; + UINT8 *Buffer; + UINTN Count; + + // + // not select, so not allowed to cut + // + if (HMainEditor.SelectStart == 0) { + StatusBarSetStatusString (L"No Block is Selected"); + return EFI_SUCCESS; + } + // + // not select, so not allowed to cut + // + if (HMainEditor.SelectEnd == 0) { + StatusBarSetStatusString (L"No Block is Selected"); + return EFI_SUCCESS; + } + + Link = HMainEditor.BufferImage->ListHead->ForwardLink; + for (Index = 0; Index < (HMainEditor.SelectEnd - 1) / 0x10; Index++) { + Link = Link->ForwardLink; + } + + Count = HMainEditor.SelectEnd - HMainEditor.SelectStart + 1; + Buffer = AllocateZeroPool (Count); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // cut the selected area + // + HBufferImageDeleteCharacterFromBuffer ( + HMainEditor.SelectStart - 1, + Count, + Buffer + ); + + // + // put to clipboard + // + HClipBoardSet (Buffer, Count); + + HBufferImageNeedRefresh = TRUE; + HBufferImageOnlyLineNeedRefresh = FALSE; + + if (!HMainEditor.BufferImage->Modified) { + HMainEditor.BufferImage->Modified = TRUE; + } + + // + // now no select area + // + HMainEditor.SelectStart = 0; + HMainEditor.SelectEnd = 0; + + return EFI_SUCCESS; +} + +/** + Paste line to file buffer. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation occurred. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HMainCommandPaste ( + VOID + ) +{ + + BOOLEAN OnlyLineRefresh; + HEFI_EDITOR_LINE *Line; + UINT8 *Buffer; + UINTN Count; + UINTN FPos; + + Count = HClipBoardGet (&Buffer); + if (Count == 0 || Buffer == NULL) { + StatusBarSetStatusString (L"Nothing to Paste"); + return EFI_SUCCESS; + } + + Line = HMainEditor.BufferImage->CurrentLine; + + OnlyLineRefresh = FALSE; + if (Line->Link.ForwardLink == HMainEditor.BufferImage->ListHead && Line->Size + Count < 0x10) { + // + // is at last line, and after paste will not exceed + // so only this line need to be refreshed + // + // if after add, the line is 0x10, then will append a new line + // so the whole page will need be refreshed + // + OnlyLineRefresh = TRUE; + + } + + FPos = 0x10 * (HMainEditor.BufferImage->BufferPosition.Row - 1) + HMainEditor.BufferImage->BufferPosition.Column - 1; + + HBufferImageAddCharacterToBuffer (FPos, Count, Buffer); + + if (OnlyLineRefresh) { + HBufferImageNeedRefresh = FALSE; + HBufferImageOnlyLineNeedRefresh = TRUE; + } else { + HBufferImageNeedRefresh = TRUE; + HBufferImageOnlyLineNeedRefresh = FALSE; + } + + if (!HMainEditor.BufferImage->Modified) { + HMainEditor.BufferImage->Modified = TRUE; + } + + return EFI_SUCCESS; + +} + +/** + Exit editor. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation occurred. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HMainCommandExit ( + VOID + ) +{ + EFI_STATUS Status; + + // + // Below is the scenario of Exit command: + // 1. IF currently opened file is not modified, exit the editor and + // Exit command ends. + // IF currently opened file is modified, do Step 2 + // + // 2. An Input Bar will be prompted: + // "File modified. Save ( Yes/No/Cancel )?" + // IF user press 'y' or 'Y', currently opened file will be saved and + // Editor exits + // IF user press 'n' or 'N', currently opened file will not be saved + // and Editor exits. + // IF user press 'c' or 'C' or ESC, Exit command ends. + // + // + // if file has been modified, so will prompt user + // whether to save the changes + // + if (HMainEditor.BufferImage->Modified) { + + Status = InputBarSetPrompt (L"Buffer modified. Save (Yes/No/Cancel) ? "); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarSetStringSize (1); + if (EFI_ERROR (Status)) { + return Status; + } + + while (1) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + + switch (InputBarGetString()[0]) { + case L'y': + case L'Y': + // + // write file back to disk + // + Status = HBufferImageSave ( + HMainEditor.BufferImage->FileImage->FileName, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + HMainEditor.BufferImage->BufferType + ); + if (!EFI_ERROR (Status)) { + HEditorExit = TRUE; + } + + return Status; + + case L'n': + case L'N': + HEditorExit = TRUE; + return EFI_SUCCESS; + + case L'c': + case L'C': + return EFI_SUCCESS; + + } + } + } + + HEditorExit = TRUE; + return EFI_SUCCESS; + +} + +/** + Load a file from disk to editor. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation occurred. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HMainCommandOpenFile ( + VOID + ) +{ + BOOLEAN Done; + EFI_STATUS Status; + EDIT_FILE_TYPE BufferType; + + BufferType = HMainEditor.BufferImage->BufferType; + + // + // This command will open a file from current working directory. + // Read-only file can also be opened. But it can not be modified. + // Below is the scenario of Open File command: + // 1. IF currently opened file has not been modified, directly go to step . + // IF currently opened file has been modified, an Input Bar will be + // prompted as : + // "File Modified. Save ( Yes/No/Cancel) ?" + // IF user press 'y' or 'Y', currently opened file will be saved. + // IF user press 'n' or 'N', currently opened file will + // not be saved. + // IF user press 'c' or 'C' or ESC, Open File command ends and + // currently opened file is still opened. + // + // 2. An Input Bar will be prompted as : "File Name to Open: " + // IF user press ESC, Open File command ends and + // currently opened file is still opened. + // Any other inputs with a Return will cause + // currently opened file close. + // + // 3. IF user input file name is an existing file , + // this file will be read and opened. + // IF user input file name is a new file, this file will be created + // and opened. This file's type ( UNICODE or ASCII ) is the same with + // the old file. + // + // + // if current file is modified, so you need to choose whether to + // save it first. + // + if (HMainEditor.BufferImage->Modified) { + + Status = InputBarSetPrompt (L"Buffer modified. Save (Yes/No/Cancel) ? "); + if (EFI_ERROR (Status)) { + return Status; + } + // + // the answer is just one character + // + Status = InputBarSetStringSize (1); + if (EFI_ERROR (Status)) { + return Status; + } + // + // loop for user's answer + // valid answer is just 'y' 'Y', 'n' 'N', 'c' 'C' + // + Done = FALSE; + while (!Done) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + + switch (InputBarGetString()[0]) { + case L'y': + case L'Y': + // + // want to save this buffer first + // + Status = HBufferImageSave ( + HMainEditor.BufferImage->FileImage->FileName, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + HMainEditor.BufferImage->BufferType + ); + if (EFI_ERROR (Status)) { + return Status; + } + + MainTitleBarRefresh ( + HMainEditor.BufferImage->BufferType == FileTypeFileBuffer?HMainEditor.BufferImage->FileImage->FileName:HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer?HMainEditor.BufferImage->DiskImage->Name:NULL, + HMainEditor.BufferImage->BufferType, + HMainEditor.BufferImage->FileImage->ReadOnly, + FALSE, + HMainEditor.ScreenSize.Column, + HMainEditor.ScreenSize.Row, + HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer?HMainEditor.BufferImage->DiskImage->Offset:HMainEditor.BufferImage->BufferType == FileTypeMemBuffer?HMainEditor.BufferImage->MemImage->Offset:0, + HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer?HMainEditor.BufferImage->DiskImage->Size :HMainEditor.BufferImage->BufferType == FileTypeMemBuffer?HMainEditor.BufferImage->MemImage->Size :0 + ); + Done = TRUE; + break; + + case L'n': + case L'N': + // + // the file won't be saved + // + Done = TRUE; + break; + + case L'c': + case L'C': + return EFI_SUCCESS; + } + } + } + // + // TO get the open file name + // + Status = InputBarSetPrompt (L"File Name to Open: "); + if (EFI_ERROR (Status)) { + HBufferImageRead ( + HMainEditor.BufferImage->FileImage->FileName, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + BufferType, + TRUE + ); + return Status; + } + + Status = InputBarSetStringSize (100); + if (EFI_ERROR (Status)) { + Status = HBufferImageRead ( + HMainEditor.BufferImage->FileImage->FileName, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + BufferType, + TRUE + ); + return Status; + } + + while (1) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + Status = HBufferImageRead ( + HMainEditor.BufferImage->FileImage->FileName, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + BufferType, + TRUE + ); + + return Status; + } + // + // THE input string length should > 0 + // + if (StrLen (InputBarGetString()) > 0) { + // + // CHECK if filename's valid + // + if (!IsValidFileName (InputBarGetString())) { + HBufferImageRead ( + HMainEditor.BufferImage->FileImage->FileName, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + BufferType, + TRUE + ); + + StatusBarSetStatusString (L"Invalid File Name"); + return EFI_SUCCESS; + } + + break; + } + } + // + // read from disk + // + Status = HBufferImageRead ( + InputBarGetString(), + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + FileTypeFileBuffer, + FALSE + ); + + if (EFI_ERROR (Status)) { + HBufferImageRead ( + HMainEditor.BufferImage->FileImage->FileName, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + BufferType, + TRUE + ); + + return EFI_LOAD_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Load a disk buffer editor. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation occurred. + @retval EFI_LOAD_ERROR A load error occurred. + @retval EFI_NOT_FOUND The disk was not found. +**/ +EFI_STATUS +HMainCommandOpenDisk ( + VOID + ) +{ + UINT64 Size; + UINT64 Offset; + CHAR16 *DeviceName; + EFI_STATUS Status; + BOOLEAN Done; + + EDIT_FILE_TYPE BufferType; + + // + // variable initialization + // + Size = 0; + Offset = 0; + BufferType = HMainEditor.BufferImage->BufferType; + + // + // if current file is modified, so you need to choose + // whether to save it first. + // + if (HMainEditor.BufferImage->Modified) { + + Status = InputBarSetPrompt (L"Buffer modified. Save (Yes/No/Cancel) ? "); + if (EFI_ERROR (Status)) { + return Status; + } + // + // the answer is just one character + // + Status = InputBarSetStringSize (1); + if (EFI_ERROR (Status)) { + return Status; + } + // + // loop for user's answer + // valid answer is just 'y' 'Y', 'n' 'N', 'c' 'C' + // + Done = FALSE; + while (!Done) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + + switch (InputBarGetString()[0]) { + case L'y': + case L'Y': + // + // want to save this buffer first + // + Status = HBufferImageSave ( + HMainEditor.BufferImage->FileImage->FileName, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + BufferType + ); + if (EFI_ERROR (Status)) { + return Status; + } + + MainTitleBarRefresh ( + HMainEditor.BufferImage->BufferType == FileTypeFileBuffer?HMainEditor.BufferImage->FileImage->FileName:HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer?HMainEditor.BufferImage->DiskImage->Name:NULL, + HMainEditor.BufferImage->BufferType, + HMainEditor.BufferImage->FileImage->ReadOnly, + FALSE, + HMainEditor.ScreenSize.Column, + HMainEditor.ScreenSize.Row, + HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer?HMainEditor.BufferImage->DiskImage->Offset:HMainEditor.BufferImage->BufferType == FileTypeMemBuffer?HMainEditor.BufferImage->MemImage->Offset:0, + HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer?HMainEditor.BufferImage->DiskImage->Size :HMainEditor.BufferImage->BufferType == FileTypeMemBuffer?HMainEditor.BufferImage->MemImage->Size :0 + ); + Done = TRUE; + break; + + case L'n': + case L'N': + // + // the file won't be saved + // + Done = TRUE; + break; + + case L'c': + case L'C': + return EFI_SUCCESS; + } + } + } + // + // get disk block device name + // + Status = InputBarSetPrompt (L"Block Device to Open: "); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarSetStringSize (100); + if (EFI_ERROR (Status)) { + return Status; + } + + while (1) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + + return EFI_SUCCESS; + } + // + // THE input string length should > 0 + // + if (StrLen (InputBarGetString()) > 0) { + break; + } + } + + DeviceName = CatSPrint(NULL, L"%s", InputBarGetString()); + if (DeviceName == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // get starting offset + // + Status = InputBarSetPrompt (L"First Block No.: "); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarSetStringSize (16); + if (EFI_ERROR (Status)) { + return Status; + } + + while (1) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + + return EFI_SUCCESS; + } + // + // THE input string length should > 0 + // + if (StrLen (InputBarGetString()) > 0) { + Status = ShellConvertStringToUint64 (InputBarGetString(), &Offset, TRUE, FALSE); + if (EFI_ERROR (Status)) { + continue; + } + + break; + } + } + // + // get Number of Blocks: + // + Status = InputBarSetPrompt (L"Number of Blocks: "); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarSetStringSize (8); + if (EFI_ERROR (Status)) { + return Status; + } + + while (1) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + + return EFI_SUCCESS; + } + // + // THE input string length should > 0 + // + if (StrLen (InputBarGetString()) > 0) { + Status = ShellConvertStringToUint64 (InputBarGetString(), &Size, TRUE, FALSE); + if (EFI_ERROR (Status)) { + continue; + } + + if (Size == 0) { + continue; + } + + break; + } + } + + Status = HBufferImageRead ( + NULL, + DeviceName, + (UINTN)Offset, + (UINTN)Size, + 0, + 0, + FileTypeDiskBuffer, + FALSE + ); + + if (EFI_ERROR (Status)) { + + HBufferImageRead ( + HMainEditor.BufferImage->FileImage->FileName, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + BufferType, + TRUE + ); + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + +/** + Load memory content to editor + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation occurred. + @retval EFI_LOAD_ERROR A load error occurred. + @retval EFI_NOT_FOUND The disk was not found. +**/ +EFI_STATUS +HMainCommandOpenMemory ( + VOID + ) +{ + UINT64 Size; + UINT64 Offset; + EFI_STATUS Status; + BOOLEAN Done; + EDIT_FILE_TYPE BufferType; + + // + // variable initialization + // + Size = 0; + Offset = 0; + BufferType = HMainEditor.BufferImage->BufferType; + + // + // if current buffer is modified, so you need to choose + // whether to save it first. + // + if (HMainEditor.BufferImage->Modified) { + + Status = InputBarSetPrompt (L"Buffer modified. Save (Yes/No/Cancel) ? "); + if (EFI_ERROR (Status)) { + return Status; + } + // + // the answer is just one character + // + Status = InputBarSetStringSize (1); + if (EFI_ERROR (Status)) { + return Status; + } + // + // loop for user's answer + // valid answer is just 'y' 'Y', 'n' 'N', 'c' 'C' + // + Done = FALSE; + while (!Done) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + + switch (InputBarGetString()[0]) { + case L'y': + case L'Y': + // + // want to save this buffer first + // + Status = HBufferImageSave ( + HMainEditor.BufferImage->FileImage->FileName, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + BufferType + ); + if (EFI_ERROR (Status)) { + return Status; + } + + MainTitleBarRefresh ( + HMainEditor.BufferImage->BufferType == FileTypeFileBuffer?HMainEditor.BufferImage->FileImage->FileName:HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer?HMainEditor.BufferImage->DiskImage->Name:NULL, + HMainEditor.BufferImage->BufferType, + HMainEditor.BufferImage->FileImage->ReadOnly, + FALSE, + HMainEditor.ScreenSize.Column, + HMainEditor.ScreenSize.Row, + HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer?HMainEditor.BufferImage->DiskImage->Offset:HMainEditor.BufferImage->BufferType == FileTypeMemBuffer?HMainEditor.BufferImage->MemImage->Offset:0, + HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer?HMainEditor.BufferImage->DiskImage->Size :HMainEditor.BufferImage->BufferType == FileTypeMemBuffer?HMainEditor.BufferImage->MemImage->Size :0 + ); + Done = TRUE; + break; + + case L'n': + case L'N': + // + // the file won't be saved + // + Done = TRUE; + break; + + case L'c': + case L'C': + return EFI_SUCCESS; + } + } + } + // + // get starting offset + // + Status = InputBarSetPrompt (L"Starting Offset: "); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarSetStringSize (8); + if (EFI_ERROR (Status)) { + return Status; + } + + while (1) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + + return EFI_SUCCESS; + } + // + // THE input string length should > 0 + // + if (StrLen (InputBarGetString()) > 0) { + Status = ShellConvertStringToUint64 (InputBarGetString(), &Offset, TRUE, FALSE); + if (EFI_ERROR (Status)) { + continue; + } + + break; + } + } + // + // get Number of Blocks: + // + Status = InputBarSetPrompt (L"Buffer Size: "); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarSetStringSize (8); + if (EFI_ERROR (Status)) { + return Status; + } + + while (1) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + + return EFI_SUCCESS; + } + // + // THE input string length should > 0 + // + if (StrLen (InputBarGetString()) > 0) { + Status = ShellConvertStringToUint64 (InputBarGetString(), &Size, TRUE, FALSE); + if (EFI_ERROR (Status)) { + continue; + } + + if (Size == 0) { + continue; + } + + break; + } + } + + if ((Offset + Size - 1)> 0xffffffff) { + StatusBarSetStatusString (L"Invalid parameter"); + return EFI_LOAD_ERROR; + } + + Status = HBufferImageRead ( + NULL, + NULL, + 0, + 0, + (UINTN)Offset, + (UINTN)Size, + FileTypeMemBuffer, + FALSE + ); + + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"Read Device Error!"); + HBufferImageRead ( + HMainEditor.BufferImage->FileImage->FileName, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + BufferType, + TRUE + ); + return EFI_NOT_FOUND; + } + return EFI_SUCCESS; + +} + +MENU_ITEM_FUNCTION HexMainControlBasedMenuFunctions[] = { + NULL, + NULL, /* Ctrl - A */ + NULL, /* Ctrl - B */ + NULL, /* Ctrl - C */ + HMainCommandSelectEnd, /* Ctrl - D */ + HMainCommandDisplayHelp, /* Ctrl - E */ + NULL, /* Ctrl - F */ + HMainCommandGoToOffset, /* Ctrl - G */ + NULL, /* Ctrl - H */ + HMainCommandOpenDisk, /* Ctrl - I */ + NULL, /* Ctrl - J */ + NULL, /* Ctrl - K */ + NULL, /* Ctrl - L */ + HMainCommandOpenMemory, /* Ctrl - M */ + NULL, /* Ctrl - N */ + HMainCommandOpenFile, /* Ctrl - O */ + NULL, /* Ctrl - P */ + HMainCommandExit, /* Ctrl - Q */ + NULL, /* Ctrl - R */ + HMainCommandSaveBuffer, /* Ctrl - S */ + HMainCommandSelectStart, /* Ctrl - T */ + NULL, /* Ctrl - U */ + HMainCommandPaste, /* Ctrl - V */ + NULL, /* Ctrl - W */ + HMainCommandCut, /* Ctrl - X */ + NULL, /* Ctrl - Y */ + NULL, /* Ctrl - Z */ +}; + +CONST EDITOR_MENU_ITEM HexEditorMenuItems[] = { + { + STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_GO_TO_OFFSET), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F1), + HMainCommandGoToOffset + }, + { + STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_SAVE_BUFFER), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F2), + HMainCommandSaveBuffer + }, + { + STRING_TOKEN(STR_EDIT_LIBMENUBAR_EXIT), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F3), + HMainCommandExit + }, + + { + STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_SELECT_START), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F4), + HMainCommandSelectStart + }, + { + STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_SELECT_END), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F5), + HMainCommandSelectEnd + }, + { + STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_CUT), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F6), + HMainCommandCut + }, + { + STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_PASTE), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F7), + HMainCommandPaste + }, + + { + STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_OPEN_FILE), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F8), + HMainCommandOpenFile + }, + { + STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_OPEN_DISK), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F9), + HMainCommandOpenDisk + }, + { + STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_OPEN_MEMORY), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F10), + HMainCommandOpenMemory + }, + + { + 0, + 0, + NULL + } +}; + +/** + Init function for MainEditor + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HMainEditorInit ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN HandleCount; + UINTN Index; + + // + // basic initialization + // + CopyMem (&HMainEditor, &HMainEditorConst, sizeof (HMainEditor)); + + // + // set screen attributes + // + HMainEditor.ColorAttributes.Colors.Foreground = gST->ConOut->Mode->Attribute & 0x000000ff; + + HMainEditor.ColorAttributes.Colors.Background = (UINT8) (gST->ConOut->Mode->Attribute >> 4); + + HOriginalColors = HMainEditor.ColorAttributes.Colors; + + HOriginalMode = gST->ConOut->Mode->Mode; + + // + // query screen size + // + gST->ConOut->QueryMode ( + gST->ConOut, + gST->ConOut->Mode->Mode, + &(HMainEditor.ScreenSize.Column), + &(HMainEditor.ScreenSize.Row) + ); + + // + // Find TextInEx in System Table ConsoleInHandle + // Per UEFI Spec, TextInEx is required for a console capable platform. + // + Status = gBS->HandleProtocol ( + gST->ConsoleInHandle, + &gEfiSimpleTextInputExProtocolGuid, + (VOID**)&HMainEditor.TextInputEx + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Find mouse in System Table ConsoleInHandle + // + Status = gBS->HandleProtocol ( + gST->ConsoleInHandle, + &gEfiSimplePointerProtocolGuid, + (VOID**)&HMainEditor.MouseInterface + ); + if (EFI_ERROR (Status)) { + // + // If there is no Simple Pointer Protocol on System Table + // + HandleBuffer = NULL; + HMainEditor.MouseInterface = NULL; + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimplePointerProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (!EFI_ERROR (Status) && HandleCount > 0) { + // + // Try to find the first available mouse device + // + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiSimplePointerProtocolGuid, + (VOID**)&HMainEditor.MouseInterface + ); + if (!EFI_ERROR (Status)) { + break; + } + } + } + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + } + + if (!EFI_ERROR (Status) && HMainEditor.MouseInterface != NULL) { + HMainEditor.MouseAccumulatorX = 0; + HMainEditor.MouseAccumulatorY = 0; + HMainEditor.MouseSupported = TRUE; + } + + // + // below will call the five components' init function + // + Status = MainTitleBarInit (L"UEFI HEXEDIT"); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_LIBEDITOR_MAINEDITOR_TITLE), gShellDebug1HiiHandle); + return EFI_LOAD_ERROR; + } + + Status = ControlHotKeyInit (HexMainControlBasedMenuFunctions); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_LIBEDITOR_MAINEDITOR_MAINMENU), gShellDebug1HiiHandle); + return EFI_LOAD_ERROR; + } + Status = MenuBarInit (HexEditorMenuItems); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_LIBEDITOR_MAINEDITOR_MAINMENU), gShellDebug1HiiHandle); + return EFI_LOAD_ERROR; + } + + Status = StatusBarInit (); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_LIBEDITOR_MAINEDITOR_STATUS), gShellDebug1HiiHandle); + return EFI_LOAD_ERROR; + } + + InputBarInit (HMainEditor.TextInputEx); + + Status = HBufferImageInit (); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_LIBEDITOR_MAINEDITOR_BUFFERIMAGE), gShellDebug1HiiHandle); + return EFI_LOAD_ERROR; + } + + Status = HClipBoardInit (); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_LIBEDITOR_MAINEDITOR_CLIPBOARD), gShellDebug1HiiHandle); + return EFI_LOAD_ERROR; + } + // + // clear whole screen and enable cursor + // + gST->ConOut->ClearScreen (gST->ConOut); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + + // + // initialize EditorFirst and EditorExit + // + HEditorFirst = TRUE; + HEditorExit = FALSE; + HEditorMouseAction = FALSE; + + return EFI_SUCCESS; +} + +/** + Cleanup function for MainEditor. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HMainEditorCleanup ( + VOID + ) +{ + EFI_STATUS Status; + + // + // call the five components' cleanup function + // + MainTitleBarCleanup (); + + MenuBarCleanup (); + + StatusBarCleanup (); + + InputBarCleanup (); + + Status = HBufferImageCleanup (); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_LIBEDITOR_BUFFERIMAGE_CLEAN), gShellDebug1HiiHandle); + } + + Status = HClipBoardCleanup (); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_LIBEDITOR_CLIPBOARD_CLEAN), gShellDebug1HiiHandle); + } + // + // restore old mode + // + if (HOriginalMode != gST->ConOut->Mode->Mode) { + gST->ConOut->SetMode (gST->ConOut, HOriginalMode); + } + + gST->ConOut->SetAttribute ( + gST->ConOut, + EFI_TEXT_ATTR (HOriginalColors.Foreground, HOriginalColors.Background) + ); + gST->ConOut->ClearScreen (gST->ConOut); + + return EFI_SUCCESS; +} + +/** + Refresh function for MainEditor. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HMainEditorRefresh ( + VOID + ) +{ + BOOLEAN NameChange; + BOOLEAN ReadChange; + + NameChange = FALSE; + ReadChange = FALSE; + + if (HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer) { + if (HMainEditor.BufferImage->DiskImage != NULL && + HBufferImageBackupVar.DiskImage != NULL && + (HMainEditor.BufferImage->DiskImage->Offset != HBufferImageBackupVar.DiskImage->Offset || + HMainEditor.BufferImage->DiskImage->Size != HBufferImageBackupVar.DiskImage->Size) ){ + NameChange = TRUE; + } + } else if (HMainEditor.BufferImage->BufferType == FileTypeMemBuffer) { + if (HMainEditor.BufferImage->MemImage != NULL && + HBufferImageBackupVar.MemImage != NULL && + (HMainEditor.BufferImage->MemImage->Offset != HBufferImageBackupVar.MemImage->Offset || + HMainEditor.BufferImage->MemImage->Size != HBufferImageBackupVar.MemImage->Size) ){ + NameChange = TRUE; + } + } else if (HMainEditor.BufferImage->BufferType == FileTypeFileBuffer) { + if ( HMainEditor.BufferImage->FileImage != NULL && + HMainEditor.BufferImage->FileImage->FileName != NULL && + HBufferImageBackupVar.FileImage != NULL && + HBufferImageBackupVar.FileImage->FileName != NULL && + StrCmp (HMainEditor.BufferImage->FileImage->FileName, HBufferImageBackupVar.FileImage->FileName) != 0 ) { + NameChange = TRUE; + } + } + if ( HMainEditor.BufferImage->FileImage != NULL && + HBufferImageBackupVar.FileImage != NULL && + HMainEditor.BufferImage->FileImage->ReadOnly != HBufferImageBackupVar.FileImage->ReadOnly ) { + ReadChange = TRUE; + } + + // + // to aVOID screen flicker + // the stall value is from experience + // + gBS->Stall (50); + + // + // call the components refresh function + // + if (HEditorFirst + || NameChange + || HMainEditor.BufferImage->BufferType != HBufferImageBackupVar.BufferType + || HBufferImageBackupVar.Modified != HMainEditor.BufferImage->Modified + || ReadChange ) { + + MainTitleBarRefresh ( + HMainEditor.BufferImage->BufferType == FileTypeFileBuffer&&HMainEditor.BufferImage->FileImage!=NULL?HMainEditor.BufferImage->FileImage->FileName:HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer&&HMainEditor.BufferImage->DiskImage!=NULL?HMainEditor.BufferImage->DiskImage->Name:NULL, + HMainEditor.BufferImage->BufferType, + (BOOLEAN)(HMainEditor.BufferImage->FileImage!=NULL?HMainEditor.BufferImage->FileImage->ReadOnly:FALSE), + HMainEditor.BufferImage->Modified, + HMainEditor.ScreenSize.Column, + HMainEditor.ScreenSize.Row, + HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer&&HMainEditor.BufferImage->DiskImage!=NULL?HMainEditor.BufferImage->DiskImage->Offset:HMainEditor.BufferImage->BufferType == FileTypeMemBuffer&&HMainEditor.BufferImage->MemImage!=NULL?HMainEditor.BufferImage->MemImage->Offset:0, + HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer&&HMainEditor.BufferImage->DiskImage!=NULL?HMainEditor.BufferImage->DiskImage->Size :HMainEditor.BufferImage->BufferType == FileTypeMemBuffer&&HMainEditor.BufferImage->MemImage!=NULL?HMainEditor.BufferImage->MemImage->Size :0 + ); + HBufferImageRefresh (); + } + if (HEditorFirst + || HBufferImageBackupVar.DisplayPosition.Row != HMainEditor.BufferImage->DisplayPosition.Row + || HBufferImageBackupVar.DisplayPosition.Column != HMainEditor.BufferImage->DisplayPosition.Column + || StatusBarGetRefresh()) { + + StatusBarRefresh ( + HEditorFirst, + HMainEditor.ScreenSize.Row, + HMainEditor.ScreenSize.Column, + (UINTN)(-1), + (UINTN)(-1), + FALSE + ); + HBufferImageRefresh (); + } + + if (HEditorFirst) { + HBufferImageRefresh (); + } + + // + // EditorFirst is now set to FALSE + // + HEditorFirst = FALSE; + + return EFI_SUCCESS; +} + +/** + Handle the mouse input. + + @param[in] MouseState The current mouse state. + @param[out] BeforeLeftButtonDown helps with selections. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation occurred. + @retval EFI_LOAD_ERROR A load error occurred. + @retval EFI_NOT_FOUND The disk was not found. +**/ +EFI_STATUS +HMainEditorHandleMouseInput ( + IN EFI_SIMPLE_POINTER_STATE MouseState, + OUT BOOLEAN *BeforeLeftButtonDown + ) +{ + + INT32 TextX; + INT32 TextY; + UINTN FRow; + UINTN FCol; + BOOLEAN HighBits; + LIST_ENTRY *Link; + HEFI_EDITOR_LINE *Line; + UINTN Index; + BOOLEAN Action; + + Action = FALSE; + + // + // have mouse movement + // + if (MouseState.RelativeMovementX || MouseState.RelativeMovementY) { + // + // handle + // + TextX = HGetTextX (MouseState.RelativeMovementX); + TextY = HGetTextY (MouseState.RelativeMovementY); + + HBufferImageAdjustMousePosition (TextX, TextY); + + Action = TRUE; + + } + + if (MouseState.LeftButton) { + HighBits = HBufferImageIsAtHighBits ( + HMainEditor.BufferImage->MousePosition.Column, + &FCol + ); + + // + // not at an movable place + // + if (FCol == 0) { + // + // now just move mouse pointer to legal position + // + // + // move mouse position to legal position + // + HMainEditor.BufferImage->MousePosition.Column -= 10; + if (HMainEditor.BufferImage->MousePosition.Column > 24) { + HMainEditor.BufferImage->MousePosition.Column--; + FCol = HMainEditor.BufferImage->MousePosition.Column / 3 + 1 + 1; + } else { + if (HMainEditor.BufferImage->MousePosition.Column < 24) { + FCol = HMainEditor.BufferImage->MousePosition.Column / 3 + 1 + 1; + } else { + // + // == 24 + // + FCol = 9; + } + } + + HighBits = TRUE; + + } + + FRow = HMainEditor.BufferImage->BufferPosition.Row + + HMainEditor.BufferImage->MousePosition.Row - + HMainEditor.BufferImage->DisplayPosition.Row; + + if (HMainEditor.BufferImage->NumLines < FRow) { + // + // dragging + // + // + // now just move mouse pointer to legal position + // + FRow = HMainEditor.BufferImage->NumLines; + HighBits = TRUE; + } + + Link = HMainEditor.BufferImage->ListHead->ForwardLink; + for (Index = 0; Index < FRow - 1; Index++) { + Link = Link->ForwardLink; + } + + Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); + + // + // dragging + // + // + // now just move mouse pointer to legal position + // + if (FCol > Line->Size) { + if (*BeforeLeftButtonDown) { + HighBits = FALSE; + + if (Line->Size == 0) { + if (FRow > 1) { + FRow--; + FCol = 16; + } else { + FRow = 1; + FCol = 1; + } + + } else { + FCol = Line->Size; + } + } else { + FCol = Line->Size + 1; + HighBits = TRUE; + } + } + + HBufferImageMovePosition (FRow, FCol, HighBits); + + HMainEditor.BufferImage->MousePosition.Row = HMainEditor.BufferImage->DisplayPosition.Row; + + HMainEditor.BufferImage->MousePosition.Column = HMainEditor.BufferImage->DisplayPosition.Column; + + *BeforeLeftButtonDown = TRUE; + + Action = TRUE; + } else { + // + // else of if LButton + // + // release LButton + // + if (*BeforeLeftButtonDown) { + Action = TRUE; + } + // + // mouse up + // + *BeforeLeftButtonDown = FALSE; + } + + if (Action) { + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; +} + +/** + Handle user key input. will route it to other components handle function. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation occurred. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HMainEditorKeyInput ( + VOID + ) +{ + EFI_KEY_DATA KeyData; + EFI_STATUS Status; + EFI_SIMPLE_POINTER_STATE MouseState; + BOOLEAN NoShiftState; + BOOLEAN LengthChange; + UINTN Size; + UINTN OldSize; + BOOLEAN BeforeMouseIsDown; + BOOLEAN MouseIsDown; + BOOLEAN FirstDown; + BOOLEAN MouseDrag; + UINTN FRow; + UINTN FCol; + UINTN SelectStartBackup; + UINTN SelectEndBackup; + + // + // variable initialization + // + OldSize = 0; + FRow = 0; + FCol = 0; + LengthChange = FALSE; + + MouseIsDown = FALSE; + FirstDown = FALSE; + MouseDrag = FALSE; + + do { + + Status = EFI_SUCCESS; + + HEditorMouseAction = FALSE; + + // + // backup some key elements, so that can aVOID some refresh work + // + HMainEditorBackup (); + + // + // wait for user key input + // + // + // change priority of checking mouse/keyboard activity dynamically + // so prevent starvation of keyboard. + // if last time, mouse moves then this time check keyboard + // + if (HMainEditor.MouseSupported) { + Status = HMainEditor.MouseInterface->GetState ( + HMainEditor.MouseInterface, + &MouseState + ); + if (!EFI_ERROR (Status)) { + + BeforeMouseIsDown = MouseIsDown; + + Status = HMainEditorHandleMouseInput (MouseState, &MouseIsDown); + + if (!EFI_ERROR (Status)) { + if (!BeforeMouseIsDown) { + // + // mouse down + // + if (MouseIsDown) { + FRow = HBufferImage.BufferPosition.Row; + FCol = HBufferImage.BufferPosition.Column; + SelectStartBackup = HMainEditor.SelectStart; + SelectEndBackup = HMainEditor.SelectEnd; + + FirstDown = TRUE; + } + } else { + + SelectStartBackup = HMainEditor.SelectStart; + SelectEndBackup = HMainEditor.SelectEnd; + + // + // begin to drag + // + if (MouseIsDown) { + if (FirstDown) { + if (MouseState.RelativeMovementX || MouseState.RelativeMovementY) { + HMainEditor.SelectStart = 0; + HMainEditor.SelectEnd = 0; + HMainEditor.SelectStart = (FRow - 1) * 0x10 + FCol; + + MouseDrag = TRUE; + FirstDown = FALSE; + } + } else { + if (( + (HBufferImage.BufferPosition.Row - 1) * + 0x10 + + HBufferImage.BufferPosition.Column + ) >= HMainEditor.SelectStart + ) { + HMainEditor.SelectEnd = (HBufferImage.BufferPosition.Row - 1) * + 0x10 + + HBufferImage.BufferPosition.Column; + } else { + HMainEditor.SelectEnd = 0; + } + } + // + // end of if RelativeX/Y + // + } else { + // + // mouse is up + // + if (MouseDrag) { + if (HBufferImageGetTotalSize () == 0) { + HMainEditor.SelectStart = 0; + HMainEditor.SelectEnd = 0; + FirstDown = FALSE; + MouseDrag = FALSE; + } + + if (( + (HBufferImage.BufferPosition.Row - 1) * + 0x10 + + HBufferImage.BufferPosition.Column + ) >= HMainEditor.SelectStart + ) { + HMainEditor.SelectEnd = (HBufferImage.BufferPosition.Row - 1) * + 0x10 + + HBufferImage.BufferPosition.Column; + } else { + HMainEditor.SelectEnd = 0; + } + + if (HMainEditor.SelectEnd == 0) { + HMainEditor.SelectStart = 0; + } + } + + FirstDown = FALSE; + MouseDrag = FALSE; + } + + if (SelectStartBackup != HMainEditor.SelectStart || SelectEndBackup != HMainEditor.SelectEnd) { + if ((SelectStartBackup - 1) / 0x10 != (HMainEditor.SelectStart - 1) / 0x10) { + HBufferImageNeedRefresh = TRUE; + } else { + if ((SelectEndBackup - 1) / 0x10 != (HMainEditor.SelectEnd - 1) / 0x10) { + HBufferImageNeedRefresh = TRUE; + } else { + HBufferImageOnlyLineNeedRefresh = TRUE; + } + } + } + } + + HEditorMouseAction = TRUE; + HBufferImageMouseNeedRefresh = TRUE; + + } else if (Status == EFI_LOAD_ERROR) { + StatusBarSetStatusString (L"Invalid Mouse Movement "); + } + } + } + + // + // CheckEvent() returns Success when non-partial key is pressed. + // + Status = gBS->CheckEvent (HMainEditor.TextInputEx->WaitForKeyEx); + if (!EFI_ERROR (Status)) { + Status = HMainEditor.TextInputEx->ReadKeyStrokeEx (HMainEditor.TextInputEx, &KeyData); + if (!EFI_ERROR (Status)) { + // + // dispatch to different components' key handling function + // so not everywhere has to set this variable + // + HBufferImageMouseNeedRefresh = TRUE; + + // + // clear previous status string + // + StatusBarSetRefresh(); + // + // NoShiftState: TRUE when no shift key is pressed. + // + NoShiftState = ((KeyData.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) == 0) || (KeyData.KeyState.KeyShiftState == EFI_SHIFT_STATE_VALID); + // + // dispatch to different components' key handling function + // + if (EFI_SUCCESS == MenuBarDispatchControlHotKey(&KeyData)) { + Status = EFI_SUCCESS; + } else if (NoShiftState && KeyData.Key.ScanCode == SCAN_NULL) { + Status = HBufferImageHandleInput (&KeyData.Key); + } else if (NoShiftState && ((KeyData.Key.ScanCode >= SCAN_UP) && (KeyData.Key.ScanCode <= SCAN_PAGE_DOWN))) { + Status = HBufferImageHandleInput (&KeyData.Key); + } else if (NoShiftState && ((KeyData.Key.ScanCode >= SCAN_F1) && KeyData.Key.ScanCode <= SCAN_F12)) { + Status = MenuBarDispatchFunctionKey (&KeyData.Key); + } else { + StatusBarSetStatusString (L"Unknown Command"); + + HBufferImageMouseNeedRefresh = FALSE; + } + + if (Status != EFI_SUCCESS && Status != EFI_OUT_OF_RESOURCES) { + // + // not already has some error status + // + if (StrCmp (L"", StatusBarGetString()) == 0) { + StatusBarSetStatusString (L"Disk Error. Try Again"); + } + } + } + // + // decide if has to set length warning + // + if (HBufferImage.BufferType != HBufferImageBackupVar.BufferType) { + LengthChange = FALSE; + } else { + // + // still the old buffer + // + if (HBufferImage.BufferType != FileTypeFileBuffer) { + Size = HBufferImageGetTotalSize (); + + switch (HBufferImage.BufferType) { + case FileTypeDiskBuffer: + OldSize = HBufferImage.DiskImage->Size * HBufferImage.DiskImage->BlockSize; + break; + + case FileTypeMemBuffer: + OldSize = HBufferImage.MemImage->Size; + break; + + default: + OldSize = 0; + break; + } + + if (!LengthChange) { + if (OldSize != Size) { + StatusBarSetStatusString (L"Disk/Mem Buffer Length should not be changed"); + } + } + + if (OldSize != Size) { + LengthChange = TRUE; + } else { + LengthChange = FALSE; + } + } + } + } + // + // after handling, refresh editor + // + HMainEditorRefresh (); + + } while (Status != EFI_OUT_OF_RESOURCES && !HEditorExit); + + return Status; +} + +/** + Backup function for MainEditor. +**/ +VOID +HMainEditorBackup ( + VOID + ) +{ + HMainEditorBackupVar.SelectStart = HMainEditor.SelectStart; + HMainEditorBackupVar.SelectEnd = HMainEditor.SelectEnd; + HBufferImageBackup (); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MainHexEditor.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MainHexEditor.h new file mode 100644 index 00000000..8cce1991 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MainHexEditor.h @@ -0,0 +1,69 @@ +/** @file + Defines the Main Editor data type - + - Global variables + - Instances of the other objects of the editor + - Main Interfaces + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _LIB_EDITOR_H_ +#define _LIB_EDITOR_H_ + +#include "HexEditor.h" + +/** + Init function for MainEditor + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HMainEditorInit ( + VOID + ); + +/** + Cleanup function for MainEditor. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HMainEditorCleanup ( + VOID + ); + +/** + Refresh function for MainEditor. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HMainEditorRefresh ( + VOID + ); + +/** + Handle user key input. will route it to other components handle function. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation occurred. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HMainEditorKeyInput ( + VOID + ); + +/** + Backup function for MainEditor. +**/ +VOID +HMainEditorBackup ( + VOID + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MemImage.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MemImage.c new file mode 100644 index 00000000..ffafb90c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MemImage.c @@ -0,0 +1,278 @@ +/** @file + Functions to deal with Mem buffer + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "HexEditor.h" + +extern EFI_HANDLE HImageHandleBackup; + +extern HEFI_EDITOR_BUFFER_IMAGE HBufferImage; + +extern BOOLEAN HBufferImageNeedRefresh; +extern BOOLEAN HBufferImageOnlyLineNeedRefresh; +extern BOOLEAN HBufferImageMouseNeedRefresh; + +extern HEFI_EDITOR_GLOBAL_EDITOR HMainEditor; + +HEFI_EDITOR_MEM_IMAGE HMemImage; +HEFI_EDITOR_MEM_IMAGE HMemImageBackupVar; + +// +// for basic initialization of HDiskImage +// +HEFI_EDITOR_MEM_IMAGE HMemImageConst = { + NULL, + 0, + 0 +}; + +/** + Initialization function for HDiskImage. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HMemImageInit ( + VOID + ) +{ + EFI_STATUS Status; + + // + // basically initialize the HMemImage + // + CopyMem (&HMemImage, &HMemImageConst, sizeof (HMemImage)); + + Status = gBS->LocateProtocol ( + &gEfiCpuIo2ProtocolGuid, + NULL, + (VOID**)&HMemImage.IoFncs + ); + if (!EFI_ERROR (Status)) { + return EFI_SUCCESS; + } else { + return EFI_LOAD_ERROR; + } +} + +/** + Backup function for HDiskImage. Only a few fields need to be backup. + This is for making the Disk buffer refresh as few as possible. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HMemImageBackup ( + VOID + ) +{ + HMemImageBackupVar.Offset = HMemImage.Offset; + HMemImageBackupVar.Size = HMemImage.Size; + + return EFI_SUCCESS; +} + +/** + Set FileName field in HFileImage. + + @param[in] Offset The offset. + @param[in] Size The size. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +HMemImageSetMemOffsetSize ( + IN UINTN Offset, + IN UINTN Size + ) +{ + + HMemImage.Offset = Offset; + HMemImage.Size = Size; + + return EFI_SUCCESS; +} + +/** + Read a disk from disk into HBufferImage. + + @param[in] Offset The offset. + @param[in] Size The size. + @param[in] Recover if is for recover, no information print. + + @retval EFI_LOAD_ERROR A load error occurred. + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +HMemImageRead ( + IN UINTN Offset, + IN UINTN Size, + IN BOOLEAN Recover + ) +{ + + EFI_STATUS Status; + void *Buffer; + CHAR16 *Str; + HEFI_EDITOR_LINE *Line; + + HBufferImage.BufferType = FileTypeMemBuffer; + + Buffer = AllocateZeroPool (Size); + if (Buffer == NULL) { + StatusBarSetStatusString (L"Read Memory Failed"); + return EFI_OUT_OF_RESOURCES; + } + + Status = HMemImage.IoFncs->Mem.Read ( + HMemImage.IoFncs, + EfiCpuIoWidthUint8, + Offset, + Size, + Buffer + ); + + if (EFI_ERROR (Status)) { + FreePool (Buffer); + StatusBarSetStatusString (L"Memory Specified Not Accessible"); + return EFI_LOAD_ERROR; + } + + HBufferImageFree (); + + Status = HBufferImageBufferToList (Buffer, Size); + FreePool (Buffer); + + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"Read Memory Failed"); + return Status; + } + + Status = HMemImageSetMemOffsetSize (Offset, Size); + + HBufferImage.DisplayPosition.Row = 2; + HBufferImage.DisplayPosition.Column = 10; + + HBufferImage.MousePosition.Row = 2; + HBufferImage.MousePosition.Column = 10; + + HBufferImage.LowVisibleRow = 1; + HBufferImage.HighBits = TRUE; + + HBufferImage.BufferPosition.Row = 1; + HBufferImage.BufferPosition.Column = 1; + + if (!Recover) { + Str = CatSPrint(NULL, L"%d Lines Read", HBufferImage.NumLines); + if (Str == NULL) { + StatusBarSetStatusString (L"Read Memory Failed"); + return EFI_OUT_OF_RESOURCES; + } + + StatusBarSetStatusString (Str); + SHELL_FREE_NON_NULL (Str); + + HMainEditor.SelectStart = 0; + HMainEditor.SelectEnd = 0; + + } + + // + // has line + // + if (HBufferImage.Lines != NULL) { + HBufferImage.CurrentLine = CR (HBufferImage.ListHead->ForwardLink, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); + } else { + // + // create a dummy line + // + Line = HBufferImageCreateLine (); + if (Line == NULL) { + StatusBarSetStatusString (L"Read Memory Failed"); + return EFI_OUT_OF_RESOURCES; + } + + HBufferImage.CurrentLine = Line; + } + + HBufferImage.Modified = FALSE; + HBufferImageNeedRefresh = TRUE; + HBufferImageOnlyLineNeedRefresh = FALSE; + HBufferImageMouseNeedRefresh = TRUE; + + return EFI_SUCCESS; + +} + +/** + Save lines in HBufferImage to disk. + + @param[in] Offset The offset. + @param[in] Size The size. + + @retval EFI_LOAD_ERROR A load error occurred. + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +HMemImageSave ( + IN UINTN Offset, + IN UINTN Size + ) +{ + + EFI_STATUS Status; + VOID *Buffer; + + // + // not modified, so directly return + // + if (HBufferImage.Modified == FALSE) { + return EFI_SUCCESS; + } + + HBufferImage.BufferType = FileTypeMemBuffer; + + Buffer = AllocateZeroPool (Size); + + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = HBufferImageListToBuffer (Buffer, Size); + if (EFI_ERROR (Status)) { + FreePool (Buffer); + return Status; + } + // + // write back to memory + // + Status = HMemImage.IoFncs->Mem.Write ( + HMemImage.IoFncs, + EfiCpuIoWidthUint8, + Offset, + Size, + Buffer + ); + + FreePool (Buffer); + + if (EFI_ERROR (Status)) { + return EFI_LOAD_ERROR; + } + // + // now not modified + // + HBufferImage.Modified = FALSE; + + return EFI_SUCCESS; +} + + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MemImage.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MemImage.h new file mode 100644 index 00000000..5a398a94 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MemImage.h @@ -0,0 +1,86 @@ +/** @file + Defines MemImage - the view of the file that is visible at any point, + as well as the event handlers for editing the file + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _LIB_MEM_IMAGE_H_ +#define _LIB_MEM_IMAGE_H_ + +#include "HexEditor.h" + +/** + Initialization function for HDiskImage. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A load error occurred. +**/ +EFI_STATUS +HMemImageInit ( + VOID + ); + +/** + Backup function for HDiskImage. Only a few fields need to be backup. + This is for making the Disk buffer refresh as few as possible. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HMemImageBackup ( + VOID + ); + +/** + Set FileName field in HFileImage. + + @param[in] Offset The offset. + @param[in] Size The size. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +HMemImageSetMemOffsetSize ( + IN UINTN Offset, + IN UINTN Size + ); + +/** + Read a disk from disk into HBufferImage. + + @param[in] Offset The offset. + @param[in] Size The size. + @param[in] Recover if is for recover, no information print. + + @retval EFI_LOAD_ERROR A load error occurred. + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +HMemImageRead ( + IN UINTN Offset, + IN UINTN Size, + IN BOOLEAN Recover + ); + +/** + Save lines in HBufferImage to disk. + + @param[in] Offset The offset. + @param[in] Size The size. + + @retval EFI_LOAD_ERROR A load error occurred. + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +HMemImageSave ( + IN UINTN Offset, + IN UINTN Size + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Misc.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Misc.c new file mode 100644 index 00000000..31ce112a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Misc.c @@ -0,0 +1,256 @@ +/** @file + Implementation of various string and line routines + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "HexEditor.h" + +extern BOOLEAN HEditorMouseAction; + +/** + Free a line and it's internal buffer. + + @param[in] Src The line to be freed. +**/ +VOID +HLineFree ( + IN HEFI_EDITOR_LINE *Src + ) +{ + if (Src == NULL) { + return ; + } + + SHELL_FREE_NON_NULL (Src); + +} + +/** + Advance to the next Count lines. + + @param[in] Count The line number to advance. + + @retval NULL An error occurred. + @return A pointer to the line after advance. +**/ +HEFI_EDITOR_LINE * +HLineAdvance ( + IN UINTN Count + ) +{ + UINTN Index; + HEFI_EDITOR_LINE *Line; + + Line = HMainEditor.BufferImage->CurrentLine; + if (Line == NULL) { + return NULL; + } + + for (Index = 0; Index < Count; Index++) { + // + // if already last line + // + if (Line->Link.ForwardLink == HMainEditor.BufferImage->ListHead) { + return NULL; + } + + Line = CR (Line->Link.ForwardLink, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); + } + + return Line; +} + +/** + Retreat to the previous Count lines. + + @param[in] Count The line number to retreat. + + @retval NULL An error occurred. + @return A pointer to the line after retreat. +**/ +HEFI_EDITOR_LINE * +HLineRetreat ( + IN UINTN Count + ) +{ + UINTN Index; + HEFI_EDITOR_LINE *Line; + + Line = HMainEditor.BufferImage->CurrentLine; + if (Line == NULL) { + return NULL; + } + + for (Index = 0; Index < Count; Index++) { + // + // already the first line + // + if (Line->Link.BackLink == HMainEditor.BufferImage->ListHead) { + return NULL; + } + + Line = CR (Line->Link.BackLink, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); + } + + return Line; +} + +/** + Advance/Retreat lines. + + @param[in] Count The line number to advance/retreat. + >0 : advance + <0: retreat + + @retval NULL An error occurred. + @return A pointer to the line after move. +**/ +HEFI_EDITOR_LINE * +HMoveLine ( + IN INTN Count + ) +{ + HEFI_EDITOR_LINE *Line; + UINTN AbsCount; + + // + // difference with MoveCurrentLine + // just return Line + // do not set currentline to Line + // + if (Count <= 0) { + AbsCount = (UINTN)ABS(Count); + Line = HLineRetreat (AbsCount); + } else { + Line = HLineAdvance ((UINTN)Count); + } + + return Line; +} + +/** + Advance/Retreat lines and set CurrentLine in BufferImage to it. + + @param[in] Count The line number to advance/retreat. + >0 : advance + <0: retreat + + @retval NULL An error occurred. + @return A pointer to the line after move. +**/ +HEFI_EDITOR_LINE * +HMoveCurrentLine ( + IN INTN Count + ) +{ + HEFI_EDITOR_LINE *Line; + UINTN AbsCount; + + // + // <0: retreat + // >0: advance + // + if (Count <= 0) { + AbsCount = (UINTN)ABS(Count); + Line = HLineRetreat (AbsCount); + } else { + Line = HLineAdvance ((UINTN)Count); + } + + if (Line == NULL) { + return NULL; + } + + HMainEditor.BufferImage->CurrentLine = Line; + + return Line; +} + + +/** + Free all the lines in HBufferImage. + Fields affected: + Lines + CurrentLine + NumLines + ListHead + + @param[in] ListHead The list head. + @param[in] Lines The lines. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HFreeLines ( + IN LIST_ENTRY *ListHead, + IN HEFI_EDITOR_LINE *Lines + ) +{ + LIST_ENTRY *Link; + HEFI_EDITOR_LINE *Line; + + // + // release all the lines + // + if (Lines != NULL) { + + Line = Lines; + Link = &(Line->Link); + do { + Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); + Link = Link->ForwardLink; + HLineFree (Line); + } while (Link != ListHead); + } + + ListHead->ForwardLink = ListHead; + ListHead->BackLink = ListHead; + + return EFI_SUCCESS; +} + +/** + Get the X information for the mouse. + + @param[in] GuidX The change. + + @return the new information. +**/ +INT32 +HGetTextX ( + IN INT32 GuidX + ) +{ + INT32 Gap; + + HMainEditor.MouseAccumulatorX += GuidX; + Gap = (HMainEditor.MouseAccumulatorX * (INT32) HMainEditor.ScreenSize.Column) / (INT32) (50 * (INT32) HMainEditor.MouseInterface->Mode->ResolutionX); + HMainEditor.MouseAccumulatorX = (HMainEditor.MouseAccumulatorX * (INT32) HMainEditor.ScreenSize.Column) % (INT32) (50 * (INT32) HMainEditor.MouseInterface->Mode->ResolutionX); + HMainEditor.MouseAccumulatorX = HMainEditor.MouseAccumulatorX / (INT32) HMainEditor.ScreenSize.Column; + return Gap; +} + +/** + Get the Y information for the mouse. + + @param[in] GuidY The change. + + @return the new information. +**/ +INT32 +HGetTextY ( + IN INT32 GuidY + ) +{ + INT32 Gap; + + HMainEditor.MouseAccumulatorY += GuidY; + Gap = (HMainEditor.MouseAccumulatorY * (INT32) HMainEditor.ScreenSize.Row) / (INT32) (50 * (INT32) HMainEditor.MouseInterface->Mode->ResolutionY); + HMainEditor.MouseAccumulatorY = (HMainEditor.MouseAccumulatorY * (INT32) HMainEditor.ScreenSize.Row) % (INT32) (50 * (INT32) HMainEditor.MouseInterface->Mode->ResolutionY); + HMainEditor.MouseAccumulatorY = HMainEditor.MouseAccumulatorY / (INT32) HMainEditor.ScreenSize.Row; + + return Gap; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Misc.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Misc.h new file mode 100644 index 00000000..4f941a60 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Misc.h @@ -0,0 +1,87 @@ +/** @file + Definitions for various line and string routines + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _LIB_MISC_H_ +#define _LIB_MISC_H_ + +#include "HexEditor.h" + +/** + Advance/Retreat lines. + + @param[in] Count The line number to advance/retreat. + >0 : advance + <0: retreat + + @retval NULL An error occurred. + @return A pointer to the line after move. +**/ +HEFI_EDITOR_LINE * +HMoveLine ( + IN INTN Count + ); + +/** + Advance/Retreat lines and set CurrentLine in BufferImage to it. + + @param[in] Count The line number to advance/retreat. + >0 : advance + <0: retreat + + @retval NULL An error occurred. + @return A pointer to the line after move. +**/ +HEFI_EDITOR_LINE * +HMoveCurrentLine ( + IN INTN Count + ); + +/** + Free all the lines in HBufferImage. + Fields affected: + Lines + CurrentLine + NumLines + ListHead + + @param[in] ListHead The list head. + @param[in] Lines The lines. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +HFreeLines ( + IN LIST_ENTRY *ListHead, + IN HEFI_EDITOR_LINE *Lines + ); + +/** + Get the X information for the mouse. + + @param[in] GuidX The change. + + @return the new information. +**/ +INT32 +HGetTextX ( + IN INT32 GuidX + ); + +/** + Get the Y information for the mouse. + + @param[in] GuidY The change. + + @return the new information. +**/ +INT32 +HGetTextY ( + IN INT32 GuidY + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/LoadPciRom.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/LoadPciRom.c new file mode 100644 index 00000000..5ac430a2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/LoadPciRom.c @@ -0,0 +1,412 @@ +/** @file + Main file for LoadPciRom shell Debug1 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2005 - 2019, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDebug1CommandsLib.h" +#include +#include +#include +#include + +/** + Connects all available drives and controllers. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_ABORTED The abort mechanism was received. +**/ +EFI_STATUS +LoadPciRomConnectAllDriversToAllControllers ( + VOID + ); + +/** + Command entry point. + + @param[in] RomBar The Rom Base address. + @param[in] RomSize The Rom size. + @param[in] FileName The file name. + + @retval EFI_SUCCESS The command completed successfully. + @retval EFI_INVALID_PARAMETER Command usage error. + @retval EFI_UNSUPPORTED Protocols unsupported. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval Other value Unknown error. +**/ +EFI_STATUS +LoadEfiDriversFromRomImage ( + VOID *RomBar, + UINTN RomSize, + CONST CHAR16 *FileName + ); + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-nc", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'loadpcirom' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunLoadPciRom ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_SHELL_FILE_INFO *FileList; + UINTN SourceSize; + UINT8 *File1Buffer; + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + BOOLEAN Connect; + CONST CHAR16 *Param; + UINTN ParamCount; + EFI_SHELL_FILE_INFO *Node; + // + // Local variable initializations + // + File1Buffer = NULL; + ShellStatus = SHELL_SUCCESS; + FileList = NULL; + + + // + // verify number of arguments + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"loadpcirom", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetCount(Package) < 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"loadpcirom"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + if (ShellCommandLineGetFlag(Package, L"-nc")) { + Connect = FALSE; + } else { + Connect = TRUE; + } + + // + // get a list with each file specified by parameters + // if parameter is a directory then add all the files below it to the list + // + for ( ParamCount = 1, Param = ShellCommandLineGetRawValue(Package, ParamCount) + ; Param != NULL + ; ParamCount++, Param = ShellCommandLineGetRawValue(Package, ParamCount) + ){ + Status = ShellOpenFileMetaArg((CHAR16*)Param, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"loadpcirom", Param); + ShellStatus = SHELL_ACCESS_DENIED; + break; + } + } + if (ShellStatus == SHELL_SUCCESS && FileList != NULL) { + // + // loop through the list and make sure we are not aborting... + // + for ( Node = (EFI_SHELL_FILE_INFO*)GetFirstNode(&FileList->Link) + ; !IsNull(&FileList->Link, &Node->Link) && !ShellGetExecutionBreakFlag() + ; Node = (EFI_SHELL_FILE_INFO*)GetNextNode(&FileList->Link, &Node->Link) + ){ + if (EFI_ERROR(Node->Status)){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"loadpcirom", Node->FullName); + ShellStatus = SHELL_INVALID_PARAMETER; + continue; + } + if (FileHandleIsDirectory(Node->Handle) == EFI_SUCCESS) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_FILE_NOT_DIR), gShellDebug1HiiHandle, L"loadpcirom", Node->FullName); + ShellStatus = SHELL_INVALID_PARAMETER; + continue; + } + SourceSize = (UINTN) Node->Info->FileSize; + File1Buffer = AllocateZeroPool (SourceSize); + if (File1Buffer == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellDebug1HiiHandle, L"loadpcirom"); + ShellStatus = SHELL_OUT_OF_RESOURCES; + continue; + } + Status = gEfiShellProtocol->ReadFile(Node->Handle, &SourceSize, File1Buffer); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_FILE_READ_FAIL), gShellDebug1HiiHandle, L"loadpcirom", Node->FullName); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = LoadEfiDriversFromRomImage ( + File1Buffer, + SourceSize, + Node->FullName + ); + + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LOAD_PCI_ROM_RES), gShellDebug1HiiHandle, Node->FullName, Status); + } + FreePool(File1Buffer); + } + } else if (ShellStatus == SHELL_SUCCESS) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_FILE_NOT_SPEC), gShellDebug1HiiHandle, "loadpcirom"); + ShellStatus = SHELL_NOT_FOUND; + } + if (FileList != NULL && !IsListEmpty(&FileList->Link)) { + Status = ShellCloseFileMetaArg(&FileList); + } + FileList = NULL; + + if (Connect) { + Status = LoadPciRomConnectAllDriversToAllControllers (); + } + } + } + + return (ShellStatus); +} + +/** + Command entry point. + + @param[in] RomBar The Rom Base address. + @param[in] RomSize The Rom size. + @param[in] FileName The file name. + + @retval EFI_SUCCESS The command completed successfully. + @retval EFI_INVALID_PARAMETER Command usage error. + @retval EFI_UNSUPPORTED Protocols unsupported. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval Other value Unknown error. +**/ +EFI_STATUS +LoadEfiDriversFromRomImage ( + VOID *RomBar, + UINTN RomSize, + CONST CHAR16 *FileName + ) + +{ + EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader; + PCI_DATA_STRUCTURE *Pcir; + UINTN ImageIndex; + UINTN RomBarOffset; + UINT32 ImageSize; + UINT16 ImageOffset; + EFI_HANDLE ImageHandle; + EFI_STATUS Status; + EFI_STATUS ReturnStatus; + CHAR16 RomFileName[280]; + EFI_DEVICE_PATH_PROTOCOL *FilePath; + BOOLEAN SkipImage; + UINT32 DestinationSize; + UINT32 ScratchSize; + UINT8 *Scratch; + VOID *ImageBuffer; + VOID *DecompressedImageBuffer; + UINT32 ImageLength; + EFI_DECOMPRESS_PROTOCOL *Decompress; + UINT32 InitializationSize; + + ImageIndex = 0; + ReturnStatus = EFI_NOT_FOUND; + RomBarOffset = (UINTN) RomBar; + + do { + + EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) (UINTN) RomBarOffset; + + if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LOADPCIROM_CORRUPT), gShellDebug1HiiHandle, L"loadpcirom", FileName, ImageIndex); +// PrintToken (STRING_TOKEN (STR_LOADPCIROM_IMAGE_CORRUPT), HiiHandle, ImageIndex); + return ReturnStatus; + } + + // + // If the pointer to the PCI Data Structure is invalid, no further images can be located. + // The PCI Data Structure must be DWORD aligned. + // + if (EfiRomHeader->PcirOffset == 0 || + (EfiRomHeader->PcirOffset & 3) != 0 || + RomBarOffset - (UINTN)RomBar + EfiRomHeader->PcirOffset + sizeof (PCI_DATA_STRUCTURE) > RomSize) { + break; + } + + Pcir = (PCI_DATA_STRUCTURE *) (UINTN) (RomBarOffset + EfiRomHeader->PcirOffset); + // + // If a valid signature is not present in the PCI Data Structure, no further images can be located. + // + if (Pcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) { + break; + } + ImageSize = Pcir->ImageLength * 512; + if (RomBarOffset - (UINTN)RomBar + ImageSize > RomSize) { + break; + } + + if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) && + (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) && + ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) || + (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER))) { + + ImageOffset = EfiRomHeader->EfiImageHeaderOffset; + InitializationSize = EfiRomHeader->InitializationSize * 512; + + if (InitializationSize <= ImageSize && ImageOffset < InitializationSize) { + + ImageBuffer = (VOID *) (UINTN) (RomBarOffset + ImageOffset); + ImageLength = InitializationSize - ImageOffset; + DecompressedImageBuffer = NULL; + + // + // decompress here if needed + // + SkipImage = FALSE; + if (EfiRomHeader->CompressionType > EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) { + SkipImage = TRUE; + } + + if (EfiRomHeader->CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) { + Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID**)&Decompress); + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR (Status)) { + SkipImage = TRUE; + } else { + SkipImage = TRUE; + Status = Decompress->GetInfo ( + Decompress, + ImageBuffer, + ImageLength, + &DestinationSize, + &ScratchSize + ); + if (!EFI_ERROR (Status)) { + DecompressedImageBuffer = AllocateZeroPool (DestinationSize); + if (ImageBuffer != NULL) { + Scratch = AllocateZeroPool (ScratchSize); + if (Scratch != NULL) { + Status = Decompress->Decompress ( + Decompress, + ImageBuffer, + ImageLength, + DecompressedImageBuffer, + DestinationSize, + Scratch, + ScratchSize + ); + if (!EFI_ERROR (Status)) { + ImageBuffer = DecompressedImageBuffer; + ImageLength = DestinationSize; + SkipImage = FALSE; + } + + FreePool (Scratch); + } + } + } + } + } + + if (!SkipImage) { + // + // load image and start image + // + UnicodeSPrint (RomFileName, sizeof (RomFileName), L"%s[%d]", FileName, ImageIndex); + FilePath = FileDevicePath (NULL, RomFileName); + + Status = gBS->LoadImage ( + TRUE, + gImageHandle, + FilePath, + ImageBuffer, + ImageLength, + &ImageHandle + ); + if (EFI_ERROR (Status)) { + // + // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created + // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now. + // If the caller doesn't have the option to defer the execution of an image, we should + // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak. + // + if (Status == EFI_SECURITY_VIOLATION) { + gBS->UnloadImage (ImageHandle); + } + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LOADPCIROM_LOAD_FAIL), gShellDebug1HiiHandle, L"loadpcirom", FileName, ImageIndex); +// PrintToken (STRING_TOKEN (STR_LOADPCIROM_LOAD_IMAGE_ERROR), HiiHandle, ImageIndex, Status); + } else { + Status = gBS->StartImage (ImageHandle, NULL, NULL); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LOADPCIROM_START_FAIL), gShellDebug1HiiHandle, L"loadpcirom", FileName, ImageIndex); +// PrintToken (STRING_TOKEN (STR_LOADPCIROM_START_IMAGE), HiiHandle, ImageIndex, Status); + } else { + ReturnStatus = Status; + } + } + } + + if (DecompressedImageBuffer != NULL) { + FreePool (DecompressedImageBuffer); + } + + } + } + + RomBarOffset = RomBarOffset + ImageSize; + ImageIndex++; + } while (((Pcir->Indicator & 0x80) == 0x00) && ((RomBarOffset - (UINTN) RomBar) < RomSize)); + + return ReturnStatus; +} + +/** + Connects all available drives and controllers. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_ABORTED The abort mechanism was received. +**/ +EFI_STATUS +LoadPciRomConnectAllDriversToAllControllers ( + VOID + ) +{ + EFI_STATUS Status; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN Index; + + Status = gBS->LocateHandleBuffer ( + AllHandles, + NULL, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + for (Index = 0; Index < HandleCount; Index++) { + if (ShellGetExecutionBreakFlag ()) { + Status = EFI_ABORTED; + break; + } + gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE); + } + + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/MemMap.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/MemMap.c new file mode 100644 index 00000000..972b2abd --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/MemMap.c @@ -0,0 +1,404 @@ +/** @file + Main file for Mode shell Debug1 function. + + (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+ (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +// +// Need full names for Standard-Format Output +// +STATIC CONST CHAR16 NameEfiReservedMemoryType[] = L"Reserved"; +STATIC CONST CHAR16 NameEfiLoaderCode[] = L"LoaderCode"; +STATIC CONST CHAR16 NameEfiLoaderData[] = L"LoaderData"; +STATIC CONST CHAR16 NameEfiBootServicesCode[] = L"BootServiceCode"; +STATIC CONST CHAR16 NameEfiBootServicesData[] = L"BootServiceData"; +STATIC CONST CHAR16 NameEfiRuntimeServicesCode[] = L"RuntimeCode"; +STATIC CONST CHAR16 NameEfiRuntimeServicesData[] = L"RuntimeData"; +STATIC CONST CHAR16 NameEfiConventionalMemory[] = L"Available"; +STATIC CONST CHAR16 NameEfiPersistentMemory[] = L"Persistent"; +STATIC CONST CHAR16 NameEfiUnusableMemory[] = L"UnusableMemory"; +STATIC CONST CHAR16 NameEfiACPIReclaimMemory[] = L"ACPIReclaimMemory"; +STATIC CONST CHAR16 NameEfiACPIMemoryNVS[] = L"ACPIMemoryNVS"; +STATIC CONST CHAR16 NameEfiMemoryMappedIO[] = L"MemoryMappedIO"; +STATIC CONST CHAR16 NameEfiMemoryMappedIOPortSpace[] = L"MemoryMappedIOPortSpace"; +STATIC CONST CHAR16 NameEfiPalCode[] = L"PalCode"; + +// +// Need short names for some memory types +// +STATIC CONST CHAR16 NameEfiBootServicesCodeShort[] = L"BS_Code"; +STATIC CONST CHAR16 NameEfiBootServicesDataShort[] = L"BS_Data"; +STATIC CONST CHAR16 NameEfiRuntimeServicesCodeShort[] = L"RT_Code"; +STATIC CONST CHAR16 NameEfiRuntimeServicesDataShort[] = L"RT_Data"; +STATIC CONST CHAR16 NameEfiUnusableMemoryShort[] = L"Unusable"; +STATIC CONST CHAR16 NameEfiACPIReclaimMemoryShort[] = L"ACPI_Recl"; +STATIC CONST CHAR16 NameEfiACPIMemoryNVSShort[] = L"ACPI_NVS"; +STATIC CONST CHAR16 NameEfiMemoryMappedIOShort[] = L"MMIO"; +STATIC CONST CHAR16 NameEfiMemoryMappedIOPortSpaceShort[] = L"MMIO_Port"; + +#include "UefiShellDebug1CommandsLib.h" + +typedef struct { + UINT32 Type; + UINT64 NumberOfPages; + LIST_ENTRY Link; +} MEMORY_LENGTH_ENTRY; + +/** + Add the length of the specified type to List. + + @param List A list to hold all pairs of . + @param Type Memory type. + @param NumberOfPages Number of pages. +**/ +VOID +AddMemoryLength ( + LIST_ENTRY *List, + UINT32 Type, + UINT64 NumberOfPages + ) +{ + MEMORY_LENGTH_ENTRY *Entry; + MEMORY_LENGTH_ENTRY *NewEntry; + LIST_ENTRY *Link; + + Entry = NULL; + for (Link = GetFirstNode (List); !IsNull (List, Link); Link = GetNextNode (List, Link)) { + Entry = BASE_CR (Link, MEMORY_LENGTH_ENTRY, Link); + if (Entry->Type >= Type) { + break; + } + } + + if ((Entry != NULL) && (Entry->Type == Type)) { + // + // The Entry is the one we look for. + // + NewEntry = Entry; + } else { + // + // The search operation breaks due to: + // 1. Type of every entry < Type --> Insert to tail + // 2. Type of an entry > Type --> Insert to previous of this entry + // + NewEntry = AllocatePool (sizeof (*NewEntry)); + if (NewEntry == NULL) { + return; + } + NewEntry->Type = Type; + NewEntry->NumberOfPages = 0; + InsertTailList (Link, &NewEntry->Link); + } + + NewEntry->NumberOfPages += NumberOfPages; +} + +/** + Function for 'memmap' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunMemMap ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + UINTN Size; + EFI_MEMORY_DESCRIPTOR *Descriptors; + UINTN MapKey; + UINTN ItemSize; + UINT32 Version; + EFI_MEMORY_DESCRIPTOR *Walker; + UINT64 ReservedPages; + UINT64 LoadCodePages; + UINT64 LoadDataPages; + UINT64 BSCodePages; + UINT64 BSDataPages; + UINT64 RTDataPages; + UINT64 RTCodePages; + UINT64 AvailPages; + UINT64 TotalPages; + UINT64 ReservedPagesSize; + UINT64 LoadCodePagesSize; + UINT64 LoadDataPagesSize; + UINT64 BSCodePagesSize; + UINT64 BSDataPagesSize; + UINT64 RTDataPagesSize; + UINT64 RTCodePagesSize; + UINT64 AvailPagesSize; + UINT64 TotalPagesSize; + UINT64 AcpiReclaimPages; + UINT64 AcpiNvsPages; + UINT64 MmioSpacePages; + UINT64 AcpiReclaimPagesSize; + UINT64 AcpiNvsPagesSize; + UINT64 MmioSpacePagesSize; + UINT64 MmioPortPages; + UINT64 MmioPortPagesSize; + UINT64 UnusableMemoryPages; + UINT64 UnusableMemoryPagesSize; + UINT64 PalCodePages; + UINT64 PalCodePagesSize; + UINT64 PersistentPages; + UINT64 PersistentPagesSize; + BOOLEAN Sfo; + LIST_ENTRY MemoryList; + MEMORY_LENGTH_ENTRY *Entry; + LIST_ENTRY *Link; + + AcpiReclaimPages = 0; + AcpiNvsPages = 0; + MmioSpacePages = 0; + TotalPages = 0; + ReservedPages = 0; + LoadCodePages = 0; + LoadDataPages = 0; + BSCodePages = 0; + BSDataPages = 0; + RTDataPages = 0; + RTCodePages = 0; + AvailPages = 0; + MmioPortPages = 0; + UnusableMemoryPages = 0; + PalCodePages = 0; + PersistentPages = 0; + Size = 0; + Descriptors = NULL; + ShellStatus = SHELL_SUCCESS; + Status = EFI_SUCCESS; + InitializeListHead (&MemoryList); + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (SfoParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"memmap", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetCount(Package) > 1) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"memmap"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = gBS->GetMemoryMap(&Size, Descriptors, &MapKey, &ItemSize, &Version); + if (Status == EFI_BUFFER_TOO_SMALL){ + Size += SIZE_1KB; + Descriptors = AllocateZeroPool(Size); + Status = gBS->GetMemoryMap(&Size, Descriptors, &MapKey, &ItemSize, &Version); + } + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MEMMAP_GET_FAILED), gShellDebug1HiiHandle, L"memmap"); + ShellStatus = SHELL_ACCESS_DENIED; + } else { + ASSERT(Version == EFI_MEMORY_DESCRIPTOR_VERSION); + + Sfo = ShellCommandLineGetFlag(Package, L"-sfo"); + if (!Sfo) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MEMMAP_LIST_HEAD), gShellDebug1HiiHandle); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_SFO_HEADER), gShellDebug1HiiHandle, L"memmap"); + } + + for ( Walker = Descriptors + ; (Walker < (EFI_MEMORY_DESCRIPTOR *) ((UINT8*)Descriptors + Size)) && (Walker != NULL) + ; Walker = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *)Walker + ItemSize) + ){ + switch (Walker->Type) { + case EfiReservedMemoryType: + ShellPrintHiiEx(-1, -1, NULL, (EFI_STRING_ID)(!Sfo?STRING_TOKEN (STR_MEMMAP_LIST_ITEM):STRING_TOKEN (STR_MEMMAP_LIST_ITEM_SFO)), gShellDebug1HiiHandle, NameEfiReservedMemoryType, Walker->PhysicalStart, Walker->PhysicalStart+MultU64x64(SIZE_4KB,Walker->NumberOfPages)-1, Walker->NumberOfPages, Walker->Attribute); + ReservedPages += Walker->NumberOfPages; + break; + case EfiLoaderCode: + ShellPrintHiiEx(-1, -1, NULL, (EFI_STRING_ID)(!Sfo?STRING_TOKEN (STR_MEMMAP_LIST_ITEM):STRING_TOKEN (STR_MEMMAP_LIST_ITEM_SFO)), gShellDebug1HiiHandle, NameEfiLoaderCode, Walker->PhysicalStart, Walker->PhysicalStart+MultU64x64(SIZE_4KB,Walker->NumberOfPages)-1, Walker->NumberOfPages, Walker->Attribute); + LoadCodePages += Walker->NumberOfPages; + TotalPages += Walker->NumberOfPages; + break; + case EfiLoaderData: + ShellPrintHiiEx(-1, -1, NULL, (EFI_STRING_ID)(!Sfo?STRING_TOKEN (STR_MEMMAP_LIST_ITEM):STRING_TOKEN (STR_MEMMAP_LIST_ITEM_SFO)), gShellDebug1HiiHandle, NameEfiLoaderData, Walker->PhysicalStart, Walker->PhysicalStart+MultU64x64(SIZE_4KB,Walker->NumberOfPages)-1, Walker->NumberOfPages, Walker->Attribute); + LoadDataPages += Walker->NumberOfPages; + TotalPages += Walker->NumberOfPages; + break; + case EfiBootServicesCode: + ShellPrintHiiEx(-1, -1, NULL, (EFI_STRING_ID)(!Sfo?STRING_TOKEN (STR_MEMMAP_LIST_ITEM):STRING_TOKEN (STR_MEMMAP_LIST_ITEM_SFO)), gShellDebug1HiiHandle, !Sfo?NameEfiBootServicesCodeShort:NameEfiBootServicesCode, Walker->PhysicalStart, Walker->PhysicalStart+MultU64x64(SIZE_4KB,Walker->NumberOfPages)-1, Walker->NumberOfPages, Walker->Attribute); + BSCodePages += Walker->NumberOfPages; + TotalPages += Walker->NumberOfPages; + break; + case EfiBootServicesData: + ShellPrintHiiEx(-1, -1, NULL, (EFI_STRING_ID)(!Sfo?STRING_TOKEN (STR_MEMMAP_LIST_ITEM):STRING_TOKEN (STR_MEMMAP_LIST_ITEM_SFO)), gShellDebug1HiiHandle, !Sfo?NameEfiBootServicesDataShort:NameEfiBootServicesData, Walker->PhysicalStart, Walker->PhysicalStart+MultU64x64(SIZE_4KB,Walker->NumberOfPages)-1, Walker->NumberOfPages, Walker->Attribute); + BSDataPages += Walker->NumberOfPages; + TotalPages += Walker->NumberOfPages; + break; + case EfiRuntimeServicesCode: + ShellPrintHiiEx(-1, -1, NULL, (EFI_STRING_ID)(!Sfo?STRING_TOKEN (STR_MEMMAP_LIST_ITEM):STRING_TOKEN (STR_MEMMAP_LIST_ITEM_SFO)), gShellDebug1HiiHandle, !Sfo?NameEfiRuntimeServicesCodeShort:NameEfiRuntimeServicesCode, Walker->PhysicalStart, Walker->PhysicalStart+MultU64x64(SIZE_4KB,Walker->NumberOfPages)-1, Walker->NumberOfPages, Walker->Attribute); + RTCodePages += Walker->NumberOfPages; + TotalPages += Walker->NumberOfPages; + break; + case EfiRuntimeServicesData: + ShellPrintHiiEx(-1, -1, NULL, (EFI_STRING_ID)(!Sfo?STRING_TOKEN (STR_MEMMAP_LIST_ITEM):STRING_TOKEN (STR_MEMMAP_LIST_ITEM_SFO)), gShellDebug1HiiHandle, !Sfo?NameEfiRuntimeServicesDataShort:NameEfiRuntimeServicesData, Walker->PhysicalStart, Walker->PhysicalStart+MultU64x64(SIZE_4KB,Walker->NumberOfPages)-1, Walker->NumberOfPages, Walker->Attribute); + RTDataPages += Walker->NumberOfPages; + TotalPages += Walker->NumberOfPages; + break; + case EfiConventionalMemory: + ShellPrintHiiEx(-1, -1, NULL, (EFI_STRING_ID)(!Sfo?STRING_TOKEN (STR_MEMMAP_LIST_ITEM):STRING_TOKEN (STR_MEMMAP_LIST_ITEM_SFO)), gShellDebug1HiiHandle, NameEfiConventionalMemory, Walker->PhysicalStart, Walker->PhysicalStart+MultU64x64(SIZE_4KB,Walker->NumberOfPages)-1, Walker->NumberOfPages, Walker->Attribute); + AvailPages += Walker->NumberOfPages; + TotalPages += Walker->NumberOfPages; + break; + case EfiPersistentMemory: + ShellPrintHiiEx(-1, -1, NULL, (EFI_STRING_ID)(!Sfo?STRING_TOKEN (STR_MEMMAP_LIST_ITEM):STRING_TOKEN (STR_MEMMAP_LIST_ITEM_SFO)), gShellDebug1HiiHandle, NameEfiPersistentMemory, Walker->PhysicalStart, Walker->PhysicalStart+MultU64x64(SIZE_4KB,Walker->NumberOfPages)-1, Walker->NumberOfPages, Walker->Attribute); + PersistentPages += Walker->NumberOfPages; + TotalPages += Walker->NumberOfPages; + break; + case EfiUnusableMemory: + ShellPrintHiiEx(-1, -1, NULL, (EFI_STRING_ID)(!Sfo?STRING_TOKEN (STR_MEMMAP_LIST_ITEM):STRING_TOKEN (STR_MEMMAP_LIST_ITEM_SFO)), gShellDebug1HiiHandle, !Sfo?NameEfiUnusableMemoryShort:NameEfiUnusableMemory, Walker->PhysicalStart, Walker->PhysicalStart+MultU64x64(SIZE_4KB,Walker->NumberOfPages)-1, Walker->NumberOfPages, Walker->Attribute); + UnusableMemoryPages += Walker->NumberOfPages; + break; + case EfiACPIReclaimMemory: + ShellPrintHiiEx(-1, -1, NULL, (EFI_STRING_ID)(!Sfo?STRING_TOKEN (STR_MEMMAP_LIST_ITEM):STRING_TOKEN (STR_MEMMAP_LIST_ITEM_SFO)), gShellDebug1HiiHandle, !Sfo?NameEfiACPIReclaimMemoryShort:NameEfiACPIReclaimMemory, Walker->PhysicalStart, Walker->PhysicalStart+MultU64x64(SIZE_4KB,Walker->NumberOfPages)-1, Walker->NumberOfPages, Walker->Attribute); + TotalPages += Walker->NumberOfPages; + AcpiReclaimPages += Walker->NumberOfPages; + break; + case EfiACPIMemoryNVS: + ShellPrintHiiEx(-1, -1, NULL, (EFI_STRING_ID)(!Sfo?STRING_TOKEN (STR_MEMMAP_LIST_ITEM):STRING_TOKEN (STR_MEMMAP_LIST_ITEM_SFO)), gShellDebug1HiiHandle, !Sfo?NameEfiACPIMemoryNVSShort:NameEfiACPIMemoryNVS, Walker->PhysicalStart, Walker->PhysicalStart+MultU64x64(SIZE_4KB,Walker->NumberOfPages)-1, Walker->NumberOfPages, Walker->Attribute); + TotalPages += Walker->NumberOfPages; + AcpiNvsPages += Walker->NumberOfPages; + break; + case EfiMemoryMappedIO: + ShellPrintHiiEx(-1, -1, NULL, (EFI_STRING_ID)(!Sfo?STRING_TOKEN (STR_MEMMAP_LIST_ITEM):STRING_TOKEN (STR_MEMMAP_LIST_ITEM_SFO)), gShellDebug1HiiHandle, !Sfo?NameEfiMemoryMappedIOShort:NameEfiMemoryMappedIO, Walker->PhysicalStart, Walker->PhysicalStart+MultU64x64(SIZE_4KB,Walker->NumberOfPages)-1, Walker->NumberOfPages, Walker->Attribute); + MmioSpacePages += Walker->NumberOfPages; + break; + case EfiMemoryMappedIOPortSpace: + ShellPrintHiiEx(-1, -1, NULL, (EFI_STRING_ID)(!Sfo?STRING_TOKEN (STR_MEMMAP_LIST_ITEM):STRING_TOKEN (STR_MEMMAP_LIST_ITEM_SFO)), gShellDebug1HiiHandle, !Sfo?NameEfiMemoryMappedIOPortSpaceShort:NameEfiMemoryMappedIOPortSpace, Walker->PhysicalStart, Walker->PhysicalStart+MultU64x64(SIZE_4KB,Walker->NumberOfPages)-1, Walker->NumberOfPages, Walker->Attribute); + MmioPortPages += Walker->NumberOfPages; + break; + case EfiPalCode: + ShellPrintHiiEx(-1, -1, NULL, (EFI_STRING_ID)(!Sfo?STRING_TOKEN (STR_MEMMAP_LIST_ITEM):STRING_TOKEN (STR_MEMMAP_LIST_ITEM_SFO)), gShellDebug1HiiHandle, NameEfiPalCode, Walker->PhysicalStart, Walker->PhysicalStart+MultU64x64(SIZE_4KB,Walker->NumberOfPages)-1, Walker->NumberOfPages, Walker->Attribute); + TotalPages += Walker->NumberOfPages; + PalCodePages += Walker->NumberOfPages; + break; + default: + // + // Shell Spec defines the SFO format. + // Do not print the OEM/OS memory usage in the SFO format, to avoid conflict with Shell Spec. + // + if (!Sfo) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MEMMAP_LIST_ITEM_OTHER), gShellDebug1HiiHandle, Walker->Type, Walker->PhysicalStart, Walker->PhysicalStart + MultU64x64 (SIZE_4KB, Walker->NumberOfPages) - 1, Walker->NumberOfPages, Walker->Attribute); + } + TotalPages += Walker->NumberOfPages; + AddMemoryLength (&MemoryList, Walker->Type, Walker->NumberOfPages); + break; + } + } + // + // print the summary + // + ReservedPagesSize = MultU64x64(SIZE_4KB,ReservedPages); + LoadCodePagesSize = MultU64x64(SIZE_4KB,LoadCodePages); + LoadDataPagesSize = MultU64x64(SIZE_4KB,LoadDataPages); + BSCodePagesSize = MultU64x64(SIZE_4KB,BSCodePages); + BSDataPagesSize = MultU64x64(SIZE_4KB,BSDataPages); + RTDataPagesSize = MultU64x64(SIZE_4KB,RTDataPages); + RTCodePagesSize = MultU64x64(SIZE_4KB,RTCodePages); + AvailPagesSize = MultU64x64(SIZE_4KB,AvailPages); + TotalPagesSize = MultU64x64(SIZE_4KB,TotalPages); + AcpiReclaimPagesSize = MultU64x64(SIZE_4KB,AcpiReclaimPages); + AcpiNvsPagesSize = MultU64x64(SIZE_4KB,AcpiNvsPages); + MmioSpacePagesSize = MultU64x64(SIZE_4KB,MmioSpacePages); + MmioPortPagesSize = MultU64x64(SIZE_4KB,MmioPortPages); + PalCodePagesSize = MultU64x64(SIZE_4KB,PalCodePages); + PersistentPagesSize = MultU64x64(SIZE_4KB,PersistentPages); + UnusableMemoryPagesSize = MultU64x64(SIZE_4KB,UnusableMemoryPages); + if (!Sfo) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MEMMAP_LIST_SUMM), gShellDebug1HiiHandle, + ReservedPages, ReservedPagesSize, + LoadCodePages, LoadCodePagesSize, + LoadDataPages, LoadDataPagesSize, + BSCodePages, BSCodePagesSize, + BSDataPages, BSDataPagesSize, + RTCodePages, RTCodePagesSize, + RTDataPages, RTDataPagesSize, + AcpiReclaimPages, AcpiReclaimPagesSize, + AcpiNvsPages, AcpiNvsPagesSize, + MmioSpacePages, MmioSpacePagesSize, + MmioPortPages, MmioPortPagesSize, + PalCodePages, PalCodePagesSize, + AvailPages, AvailPagesSize, + PersistentPages, PersistentPagesSize + ); + + // + // Print out the total memory usage for OEM/OS types in the order of type. + // + for (Link = GetFirstNode (&MemoryList); !IsNull (&MemoryList, Link); Link = GetNextNode (&MemoryList, Link)) { + Entry = BASE_CR (Link, MEMORY_LENGTH_ENTRY, Link); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MEMMAP_LIST_SUMM_OTHER), gShellDebug1HiiHandle, + Entry->Type, Entry->NumberOfPages, MultU64x64 (SIZE_4KB, Entry->NumberOfPages) + ); + } + + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MEMMAP_LIST_SUMM2), gShellDebug1HiiHandle, + DivU64x32(MultU64x64(SIZE_4KB,TotalPages), SIZE_1MB), TotalPagesSize + ); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MEMMAP_LIST_SUMM_SFO), gShellDebug1HiiHandle, + TotalPagesSize, + ReservedPagesSize, + BSCodePagesSize, + BSDataPagesSize, + RTCodePagesSize, + RTDataPagesSize, + LoadCodePagesSize, + LoadDataPagesSize, + AvailPagesSize, + MmioSpacePagesSize, + MmioPortPagesSize, + UnusableMemoryPagesSize, + AcpiReclaimPagesSize, + AcpiNvsPagesSize, + PalCodePagesSize, + PersistentPagesSize + ); + } + } + } + ShellCommandLineFreeVarList (Package); + } + + if (Descriptors != NULL) { + FreePool(Descriptors); + } + + // + // Free the memory list. + // + for (Link = GetFirstNode (&MemoryList); !IsNull (&MemoryList, Link); ) { + Link = RemoveEntryList (Link); + } + + return (ShellStatus); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Mm.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Mm.c new file mode 100644 index 00000000..bc5b4ca1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Mm.c @@ -0,0 +1,631 @@ +/** @file + Main file for Mm shell Debug1 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2005 - 2017, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDebug1CommandsLib.h" +#include +#include +#include +#include + +typedef enum { + ShellMmMemory, + ShellMmMemoryMappedIo, + ShellMmIo, + ShellMmPci, + ShellMmPciExpress +} SHELL_MM_ACCESS_TYPE; + +CONST UINT16 mShellMmAccessTypeStr[] = { + STRING_TOKEN (STR_MM_MEM), + STRING_TOKEN (STR_MM_MMIO), + STRING_TOKEN (STR_MM_IO), + STRING_TOKEN (STR_MM_PCI), + STRING_TOKEN (STR_MM_PCIE) +}; + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-mmio", TypeFlag}, + {L"-mem", TypeFlag}, + {L"-io", TypeFlag}, + {L"-pci", TypeFlag}, + {L"-pcie", TypeFlag}, + {L"-n", TypeFlag}, + {L"-w", TypeValue}, + {NULL, TypeMax} + }; + +CONST UINT64 mShellMmMaxNumber[] = { + 0, MAX_UINT8, MAX_UINT16, 0, MAX_UINT32, 0, 0, 0, MAX_UINT64 +}; +CONST EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH mShellMmRootBridgeIoWidth[] = { + 0, EfiPciWidthUint8, EfiPciWidthUint16, 0, EfiPciWidthUint32, 0, 0, 0, EfiPciWidthUint64 +}; +CONST EFI_CPU_IO_PROTOCOL_WIDTH mShellMmCpuIoWidth[] = { + 0, EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, 0, EfiCpuIoWidthUint32, 0, 0, 0, EfiCpuIoWidthUint64 +}; + +/** + Extract the PCI segment, bus, device, function, register from + from a PCI or PCIE format of address.. + + @param[in] PciFormat Whether the address is of PCI format of PCIE format. + @param[in] Address PCI or PCIE address. + @param[out] Segment PCI segment number. + @param[out] Bus PCI bus number. + @param[out] Device PCI device number. + @param[out] Function PCI function number. + @param[out] Register PCI register offset. +**/ +VOID +ShellMmDecodePciAddress ( + IN BOOLEAN PciFormat, + IN UINT64 Address, + OUT UINT32 *Segment, + OUT UINT8 *Bus, + OUT UINT8 *Device, OPTIONAL + OUT UINT8 *Function, OPTIONAL + OUT UINT32 *Register OPTIONAL + ) +{ + if (PciFormat) { + // + // PCI Configuration Space.The address will have the format ssssbbddffrr, + // where ssss = Segment, bb = Bus, dd = Device, ff = Function and rr = Register. + // + *Segment = (UINT32) (RShiftU64 (Address, 32) & 0xFFFF); + *Bus = (UINT8) (((UINT32) Address) >> 24); + + if (Device != NULL) { + *Device = (UINT8) (((UINT32) Address) >> 16); + } + if (Function != NULL) { + *Function = (UINT8) (((UINT32) Address) >> 8); + } + if (Register != NULL) { + *Register = (UINT8) Address; + } + } else { + // + // PCI Express Configuration Space.The address will have the format ssssssbbddffrrr, + // where ssss = Segment, bb = Bus, dd = Device, ff = Function and rrr = Register. + // + *Segment = (UINT32) (RShiftU64 (Address, 36) & 0xFFFF); + *Bus = (UINT8) RShiftU64 (Address, 28); + if (Device != NULL) { + *Device = (UINT8) (((UINT32) Address) >> 20); + } + if (Function != NULL) { + *Function = (UINT8) (((UINT32) Address) >> 12); + } + if (Register != NULL) { + *Register = (UINT32) (Address & 0xFFF); + } + } +} + +/** + Read or write some data from or into the Address. + + @param[in] AccessType Access type. + @param[in] PciRootBridgeIo PciRootBridgeIo instance. + @param[in] CpuIo CpuIo instance. + @param[in] Read TRUE for read, FALSE for write. + @param[in] Addresss The memory location to access. + @param[in] Size The size of Buffer in Width sized units. + @param[in, out] Buffer The buffer to read into or write from. +**/ +VOID +ShellMmAccess ( + IN SHELL_MM_ACCESS_TYPE AccessType, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + IN EFI_CPU_IO2_PROTOCOL *CpuIo, + IN BOOLEAN Read, + IN UINT64 Address, + IN UINTN Size, + IN OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM RootBridgeIoMem; + EFI_CPU_IO_PROTOCOL_IO_MEM CpuIoMem; + UINT32 Segment; + UINT8 Bus; + UINT8 Device; + UINT8 Function; + UINT32 Register; + + if (AccessType == ShellMmMemory) { + if (Read) { + CopyMem (Buffer, (VOID *) (UINTN) Address, Size); + } else { + CopyMem ((VOID *) (UINTN) Address, Buffer, Size); + } + } else { + RootBridgeIoMem = NULL; + CpuIoMem = NULL; + switch (AccessType) { + case ShellMmPci: + case ShellMmPciExpress: + ASSERT (PciRootBridgeIo != NULL); + ShellMmDecodePciAddress ((BOOLEAN) (AccessType == ShellMmPci), Address, &Segment, &Bus, &Device, &Function, &Register); + if (Read) { + Status = PciRootBridgeIo->Pci.Read ( + PciRootBridgeIo, mShellMmRootBridgeIoWidth[Size], + EFI_PCI_ADDRESS (Bus, Device, Function, Register), + 1, Buffer + ); + } else { + Status = PciRootBridgeIo->Pci.Write ( + PciRootBridgeIo, mShellMmRootBridgeIoWidth[Size], + EFI_PCI_ADDRESS (Bus, Device, Function, Register), + 1, Buffer + ); + } + ASSERT_EFI_ERROR (Status); + return; + + case ShellMmMemoryMappedIo: + if (PciRootBridgeIo != NULL) { + RootBridgeIoMem = Read ? PciRootBridgeIo->Mem.Read : PciRootBridgeIo->Mem.Write; + } + if (CpuIo != NULL) { + CpuIoMem = Read ? CpuIo->Mem.Read : CpuIo->Mem.Write; + } + break; + + case ShellMmIo: + if (PciRootBridgeIo != NULL) { + RootBridgeIoMem = Read ? PciRootBridgeIo->Io.Read : PciRootBridgeIo->Io.Write; + } + if (CpuIo != NULL) { + CpuIoMem = Read ? CpuIo->Io.Read : CpuIo->Io.Write; + } + break; + default: + ASSERT (FALSE); + break; + } + + Status = EFI_UNSUPPORTED; + if (RootBridgeIoMem != NULL) { + Status = RootBridgeIoMem (PciRootBridgeIo, mShellMmRootBridgeIoWidth[Size], Address, 1, Buffer); + } + if (EFI_ERROR (Status) && (CpuIoMem != NULL)) { + Status = CpuIoMem (CpuIo, mShellMmCpuIoWidth[Size], Address, 1, Buffer); + } + + if (EFI_ERROR (Status)) { + if (AccessType == ShellMmIo) { + switch (Size) { + case 1: + if (Read) { + *(UINT8 *) Buffer = IoRead8 ((UINTN) Address); + } else { + IoWrite8 ((UINTN) Address, *(UINT8 *) Buffer); + } + break; + case 2: + if (Read) { + *(UINT16 *) Buffer = IoRead16 ((UINTN) Address); + } else { + IoWrite16 ((UINTN) Address, *(UINT16 *) Buffer); + } + break; + case 4: + if (Read) { + *(UINT32 *) Buffer = IoRead32 ((UINTN) Address); + } else { + IoWrite32 ((UINTN) Address, *(UINT32 *) Buffer); + } + break; + case 8: + if (Read) { + *(UINT64 *) Buffer = IoRead64 ((UINTN) Address); + } else { + IoWrite64 ((UINTN) Address, *(UINT64 *) Buffer); + } + break; + default: + ASSERT (FALSE); + break; + } + } else { + switch (Size) { + case 1: + if (Read) { + *(UINT8 *) Buffer = MmioRead8 ((UINTN) Address); + } else { + MmioWrite8 ((UINTN) Address, *(UINT8 *) Buffer); + } + break; + case 2: + if (Read) { + *(UINT16 *) Buffer = MmioRead16 ((UINTN) Address); + } else { + MmioWrite16 ((UINTN) Address, *(UINT16 *) Buffer); + } + break; + case 4: + if (Read) { + *(UINT32 *) Buffer = MmioRead32 ((UINTN) Address); + } else { + MmioWrite32 ((UINTN) Address, *(UINT32 *) Buffer); + } + break; + case 8: + if (Read) { + *(UINT64 *) Buffer = MmioRead64 ((UINTN) Address); + } else { + MmioWrite64 ((UINTN) Address, *(UINT64 *) Buffer); + } + break; + default: + ASSERT (FALSE); + break; + } + } + } + } +} + +/** + Find the CpuIo instance and PciRootBridgeIo instance in the platform. + If there are multiple PciRootBridgeIo instances, the instance which manages + the Address is returned. + + @param[in] AccessType Access type. + @param[in] Address Address to access. + @param[out] CpuIo Return the CpuIo instance. + @param[out] PciRootBridgeIo Return the proper PciRootBridgeIo instance. + + @retval TRUE There are PciRootBridgeIo instances in the platform. + @retval FALSE There isn't PciRootBridgeIo instance in the platform. +**/ +BOOLEAN +ShellMmLocateIoProtocol ( + IN SHELL_MM_ACCESS_TYPE AccessType, + IN UINT64 Address, + OUT EFI_CPU_IO2_PROTOCOL **CpuIo, + OUT EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL **PciRootBridgeIo + ) +{ + EFI_STATUS Status; + UINTN Index; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *Io; + UINT32 Segment; + UINT8 Bus; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors; + + Status = gBS->LocateProtocol (&gEfiCpuIo2ProtocolGuid, NULL, (VOID **) CpuIo); + if (EFI_ERROR (Status)) { + *CpuIo = NULL; + } + + *PciRootBridgeIo = NULL; + HandleBuffer = NULL; + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiPciRootBridgeIoProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status) || (HandleCount == 0) || (HandleBuffer == NULL)) { + return FALSE; + } + + Segment = 0; + Bus = 0; + if ((AccessType == ShellMmPci) || (AccessType == ShellMmPciExpress)) { + ShellMmDecodePciAddress ((BOOLEAN) (AccessType == ShellMmPci), Address, &Segment, &Bus, NULL, NULL, NULL); + } + + // + // Find the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL of the specified segment & bus number + // + for (Index = 0; (Index < HandleCount) && (*PciRootBridgeIo == NULL); Index++) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiPciRootBridgeIoProtocolGuid, + (VOID *) &Io + ); + if (EFI_ERROR (Status)) { + continue; + } + + if ((((AccessType == ShellMmPci) || (AccessType == ShellMmPciExpress)) && (Io->SegmentNumber == Segment)) || + ((AccessType == ShellMmIo) || (AccessType == ShellMmMemoryMappedIo)) + ) { + Status = Io->Configuration (Io, (VOID **) &Descriptors); + if (!EFI_ERROR (Status)) { + while (Descriptors->Desc != ACPI_END_TAG_DESCRIPTOR) { + // + // Compare the segment and bus range for PCI/PCIE access + // + if ((Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) && + ((AccessType == ShellMmPci) || (AccessType == ShellMmPciExpress)) && + ((Bus >= Descriptors->AddrRangeMin) && (Bus <= Descriptors->AddrRangeMax)) + ) { + *PciRootBridgeIo = Io; + break; + + // + // Compare the address range for MMIO/IO access + // + } else if ((((Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_IO) && (AccessType == ShellMmIo)) || + ((Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) && (AccessType == ShellMmMemoryMappedIo)) + ) && ((Address >= Descriptors->AddrRangeMin) && (Address <= Descriptors->AddrRangeMax)) + ) { + *PciRootBridgeIo = Io; + break; + } + Descriptors++; + } + } + } + } + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + + return TRUE; +} + +/** + Function for 'mm' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunMm ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + EFI_CPU_IO2_PROTOCOL *CpuIo; + UINT64 Address; + UINT64 Value; + SHELL_MM_ACCESS_TYPE AccessType; + UINT64 Buffer; + UINTN Index; + UINTN Size; + BOOLEAN Complete; + CHAR16 *InputStr; + BOOLEAN Interactive; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CONST CHAR16 *Temp; + BOOLEAN HasPciRootBridgeIo; + + Value = 0; + Address = 0; + ShellStatus = SHELL_SUCCESS; + InputStr = NULL; + Size = 1; + AccessType = ShellMmMemory; + + // + // Parse arguments + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR (Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"mm", ProblemParam); + FreePool (ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } else { + ASSERT (FALSE); + } + } else { + if (ShellCommandLineGetCount (Package) < 2) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"mm"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } else if (ShellCommandLineGetCount (Package) > 3) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mm"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } else if (ShellCommandLineGetFlag (Package, L"-w") && ShellCommandLineGetValue (Package, L"-w") == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDebug1HiiHandle, L"mm", L"-w"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } else { + if (ShellCommandLineGetFlag (Package, L"-mmio")) { + AccessType = ShellMmMemoryMappedIo; + if (ShellCommandLineGetFlag (Package, L"-mem") + || ShellCommandLineGetFlag (Package, L"-io") + || ShellCommandLineGetFlag (Package, L"-pci") + || ShellCommandLineGetFlag (Package, L"-pcie") + ) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mm"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + } else if (ShellCommandLineGetFlag (Package, L"-mem")) { + AccessType = ShellMmMemory; + if (ShellCommandLineGetFlag (Package, L"-io") + || ShellCommandLineGetFlag (Package, L"-pci") + || ShellCommandLineGetFlag (Package, L"-pcie") + ) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mm"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + } else if (ShellCommandLineGetFlag (Package, L"-io")) { + AccessType = ShellMmIo; + if (ShellCommandLineGetFlag (Package, L"-pci") + || ShellCommandLineGetFlag (Package, L"-pcie") + ) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mm"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + } else if (ShellCommandLineGetFlag (Package, L"-pci")) { + AccessType = ShellMmPci; + if (ShellCommandLineGetFlag (Package, L"-pcie") + ) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mm"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + } else if (ShellCommandLineGetFlag (Package, L"-pcie")) { + AccessType = ShellMmPciExpress; + } + } + + // + // Non interactive for a script file or for the specific parameter + // + Interactive = TRUE; + if (gEfiShellProtocol->BatchIsActive () || ShellCommandLineGetFlag (Package, L"-n")) { + Interactive = FALSE; + } + + Temp = ShellCommandLineGetValue (Package, L"-w"); + if (Temp != NULL) { + Size = ShellStrToUintn (Temp); + } + if ((Size != 1) && (Size != 2) && (Size != 4) && (Size != 8)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellDebug1HiiHandle, L"mm", Temp, L"-w"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + + Temp = ShellCommandLineGetRawValue (Package, 1); + Status = ShellConvertStringToUint64 (Temp, &Address, TRUE, FALSE); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"mm", Temp); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + + if ((Address & (Size - 1)) != 0) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_NOT_ALIGNED), gShellDebug1HiiHandle, L"mm", Address); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + + // + // locate IO protocol interface + // + HasPciRootBridgeIo = ShellMmLocateIoProtocol (AccessType, Address, &CpuIo, &PciRootBridgeIo); + if ((AccessType == ShellMmPci) || (AccessType == ShellMmPciExpress)) { + if (!HasPciRootBridgeIo) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PCIRBIO_NF), gShellDebug1HiiHandle, L"mm"); + ShellStatus = SHELL_NOT_FOUND; + goto Done; + } + if (PciRootBridgeIo == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_PCIE_ADDRESS_RANGE), gShellDebug1HiiHandle, L"mm", Address); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + } + + // + // Mode 1: Directly set a value + // + Temp = ShellCommandLineGetRawValue (Package, 2); + if (Temp != NULL) { + Status = ShellConvertStringToUint64 (Temp, &Value, TRUE, FALSE); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"mm", Temp); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + + if (Value > mShellMmMaxNumber[Size]) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"mm", Temp); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + + ShellMmAccess (AccessType, PciRootBridgeIo, CpuIo, FALSE, Address, Size, &Value); + goto Done; + } + + // + // Mode 2: Directly show a value + // + if (!Interactive) { + if (!gEfiShellProtocol->BatchIsActive ()) { + ShellPrintHiiEx (-1, -1, NULL, mShellMmAccessTypeStr[AccessType], gShellDebug1HiiHandle); + } + ShellMmAccess (AccessType, PciRootBridgeIo, CpuIo, TRUE, Address, Size, &Buffer); + + if (!gEfiShellProtocol->BatchIsActive ()) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_ADDRESS), gShellDebug1HiiHandle, Address); + } + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_BUF), gShellDebug1HiiHandle, Size * 2, Buffer & mShellMmMaxNumber[Size]); + ShellPrintEx (-1, -1, L"\r\n"); + goto Done; + } + + // + // Mode 3: Show or set values in interactive mode + // + Complete = FALSE; + do { + ShellMmAccess (AccessType, PciRootBridgeIo, CpuIo, TRUE, Address, Size, &Buffer); + ShellPrintHiiEx (-1, -1, NULL, mShellMmAccessTypeStr[AccessType], gShellDebug1HiiHandle); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_ADDRESS), gShellDebug1HiiHandle, Address); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_BUF), gShellDebug1HiiHandle, Size * 2, Buffer & mShellMmMaxNumber[Size]); + ShellPrintEx (-1, -1, L" > "); + // + // wait user input to modify + // + if (InputStr != NULL) { + FreePool (InputStr); + InputStr = NULL; + } + ShellPromptForResponse (ShellPromptResponseTypeFreeform, NULL, (VOID**) &InputStr); + + if (InputStr != NULL) { + // + // skip space characters + // + for (Index = 0; InputStr[Index] == ' '; Index++); + + if (InputStr[Index] != CHAR_NULL) { + if ((InputStr[Index] == '.') || (InputStr[Index] == 'q') || (InputStr[Index] == 'Q')) { + Complete = TRUE; + } else if (!EFI_ERROR (ShellConvertStringToUint64 (InputStr + Index, &Buffer, TRUE, TRUE)) && + (Buffer <= mShellMmMaxNumber[Size]) + ) { + ShellMmAccess (AccessType, PciRootBridgeIo, CpuIo, FALSE, Address, Size, &Buffer); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_ERROR), gShellDebug1HiiHandle, L"mm"); + continue; + } + } + } + + Address += Size; + ShellPrintEx (-1, -1, L"\r\n"); + } while (!Complete); + } + ASSERT (ShellStatus == SHELL_SUCCESS); + +Done: + if (InputStr != NULL) { + FreePool (InputStr); + } + if (Package != NULL) { + ShellCommandLineFreeVarList (Package); + } + return ShellStatus; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Mode.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Mode.c new file mode 100644 index 00000000..ef093da6 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Mode.c @@ -0,0 +1,122 @@ +/** @file + Main file for Mode shell Debug1 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDebug1CommandsLib.h" + +/** + Function for 'mode' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunMode ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + UINTN NewCol; + UINTN NewRow; + UINTN Col; + UINTN Row; + CONST CHAR16 *Temp; + BOOLEAN Done; + INT32 LoopVar; + + ShellStatus = SHELL_SUCCESS; + Status = EFI_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"mode", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetCount(Package) > 3) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mode"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetCount(Package) == 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"mode"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetCount(Package) == 3) { + Temp = ShellCommandLineGetRawValue(Package, 1); + if (!ShellIsHexOrDecimalNumber(Temp, FALSE, FALSE)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"mode", Temp); + ShellStatus = SHELL_INVALID_PARAMETER; + } + NewCol = ShellStrToUintn(Temp); + Temp = ShellCommandLineGetRawValue(Package, 2); + if (!ShellIsHexOrDecimalNumber(Temp, FALSE, FALSE)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"mode", Temp); + ShellStatus = SHELL_INVALID_PARAMETER; + } + NewRow = ShellStrToUintn(Temp); + + for (LoopVar = 0, Done = FALSE; LoopVar < gST->ConOut->Mode->MaxMode && ShellStatus == SHELL_SUCCESS ; LoopVar++) { + Status = gST->ConOut->QueryMode(gST->ConOut, LoopVar, &Col, &Row); + if (EFI_ERROR(Status)) { + continue; + } + if (Col == NewCol && Row == NewRow) { + Status = gST->ConOut->SetMode(gST->ConOut, LoopVar); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MODE_SET_FAIL), gShellDebug1HiiHandle, L"mode"); + ShellStatus = SHELL_DEVICE_ERROR; + } else { + // worked fine... + Done = TRUE; + } + break; + } + } + + if (!Done) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MODE_NO_MATCH), gShellDebug1HiiHandle, L"mode"); + ShellStatus = SHELL_INVALID_PARAMETER; + } + + } else if (ShellCommandLineGetCount(Package) == 1) { + // + // print out valid + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MODE_LIST_HEAD), gShellDebug1HiiHandle); + for (LoopVar = 0, Done = FALSE; LoopVar < gST->ConOut->Mode->MaxMode && ShellStatus == SHELL_SUCCESS ; LoopVar++) { + Status = gST->ConOut->QueryMode(gST->ConOut, LoopVar, &Col, &Row); + if (EFI_ERROR(Status)) { + continue; + } + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MODE_LIST_ITEM), gShellDebug1HiiHandle, Col, Row, LoopVar == gST->ConOut->Mode->Mode?L'*':L' '); + } + } + ShellCommandLineFreeVarList (Package); + } + + return (ShellStatus); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Pci.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Pci.c new file mode 100644 index 00000000..6cb5cf23 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Pci.c @@ -0,0 +1,5815 @@ +/** @file + Main file for Pci shell Debug1 function. + + Copyright (c) 2005 - 2021, Intel Corporation. All rights reserved.
+ (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDebug1CommandsLib.h" +#include +#include +#include +#include +#include "Pci.h" + +// +// Printable strings for Pci class code +// +typedef struct { + CHAR16 *BaseClass; // Pointer to the PCI base class string + CHAR16 *SubClass; // Pointer to the PCI sub class string + CHAR16 *PIFClass; // Pointer to the PCI programming interface string +} PCI_CLASS_STRINGS; + +// +// a structure holding a single entry, which also points to its lower level +// class +// +typedef struct PCI_CLASS_ENTRY_TAG { + UINT8 Code; // Class, subclass or I/F code + CHAR16 *DescText; // Description string + struct PCI_CLASS_ENTRY_TAG *LowerLevelClass; // Subclass or I/F if any +} PCI_CLASS_ENTRY; + +// +// Declarations of entries which contain printable strings for class codes +// in PCI configuration space +// +PCI_CLASS_ENTRY PCIBlankEntry[]; +PCI_CLASS_ENTRY PCISubClass_00[]; +PCI_CLASS_ENTRY PCISubClass_01[]; +PCI_CLASS_ENTRY PCISubClass_02[]; +PCI_CLASS_ENTRY PCISubClass_03[]; +PCI_CLASS_ENTRY PCISubClass_04[]; +PCI_CLASS_ENTRY PCISubClass_05[]; +PCI_CLASS_ENTRY PCISubClass_06[]; +PCI_CLASS_ENTRY PCISubClass_07[]; +PCI_CLASS_ENTRY PCISubClass_08[]; +PCI_CLASS_ENTRY PCISubClass_09[]; +PCI_CLASS_ENTRY PCISubClass_0a[]; +PCI_CLASS_ENTRY PCISubClass_0b[]; +PCI_CLASS_ENTRY PCISubClass_0c[]; +PCI_CLASS_ENTRY PCISubClass_0d[]; +PCI_CLASS_ENTRY PCISubClass_0e[]; +PCI_CLASS_ENTRY PCISubClass_0f[]; +PCI_CLASS_ENTRY PCISubClass_10[]; +PCI_CLASS_ENTRY PCISubClass_11[]; +PCI_CLASS_ENTRY PCISubClass_12[]; +PCI_CLASS_ENTRY PCISubClass_13[]; +PCI_CLASS_ENTRY PCIPIFClass_0100[]; +PCI_CLASS_ENTRY PCIPIFClass_0101[]; +PCI_CLASS_ENTRY PCIPIFClass_0105[]; +PCI_CLASS_ENTRY PCIPIFClass_0106[]; +PCI_CLASS_ENTRY PCIPIFClass_0107[]; +PCI_CLASS_ENTRY PCIPIFClass_0108[]; +PCI_CLASS_ENTRY PCIPIFClass_0109[]; +PCI_CLASS_ENTRY PCIPIFClass_0300[]; +PCI_CLASS_ENTRY PCIPIFClass_0604[]; +PCI_CLASS_ENTRY PCIPIFClass_0609[]; +PCI_CLASS_ENTRY PCIPIFClass_060b[]; +PCI_CLASS_ENTRY PCIPIFClass_0700[]; +PCI_CLASS_ENTRY PCIPIFClass_0701[]; +PCI_CLASS_ENTRY PCIPIFClass_0703[]; +PCI_CLASS_ENTRY PCIPIFClass_0800[]; +PCI_CLASS_ENTRY PCIPIFClass_0801[]; +PCI_CLASS_ENTRY PCIPIFClass_0802[]; +PCI_CLASS_ENTRY PCIPIFClass_0803[]; +PCI_CLASS_ENTRY PCIPIFClass_0904[]; +PCI_CLASS_ENTRY PCIPIFClass_0c00[]; +PCI_CLASS_ENTRY PCIPIFClass_0c03[]; +PCI_CLASS_ENTRY PCIPIFClass_0c07[]; +PCI_CLASS_ENTRY PCIPIFClass_0d01[]; +PCI_CLASS_ENTRY PCIPIFClass_0e00[]; + +// +// Base class strings entries +// +PCI_CLASS_ENTRY gClassStringList[] = { + { + 0x00, + L"Pre 2.0 device", + PCISubClass_00 + }, + { + 0x01, + L"Mass Storage Controller", + PCISubClass_01 + }, + { + 0x02, + L"Network Controller", + PCISubClass_02 + }, + { + 0x03, + L"Display Controller", + PCISubClass_03 + }, + { + 0x04, + L"Multimedia Device", + PCISubClass_04 + }, + { + 0x05, + L"Memory Controller", + PCISubClass_05 + }, + { + 0x06, + L"Bridge Device", + PCISubClass_06 + }, + { + 0x07, + L"Simple Communications Controllers", + PCISubClass_07 + }, + { + 0x08, + L"Base System Peripherals", + PCISubClass_08 + }, + { + 0x09, + L"Input Devices", + PCISubClass_09 + }, + { + 0x0a, + L"Docking Stations", + PCISubClass_0a + }, + { + 0x0b, + L"Processors", + PCISubClass_0b + }, + { + 0x0c, + L"Serial Bus Controllers", + PCISubClass_0c + }, + { + 0x0d, + L"Wireless Controllers", + PCISubClass_0d + }, + { + 0x0e, + L"Intelligent IO Controllers", + PCISubClass_0e + }, + { + 0x0f, + L"Satellite Communications Controllers", + PCISubClass_0f + }, + { + 0x10, + L"Encryption/Decryption Controllers", + PCISubClass_10 + }, + { + 0x11, + L"Data Acquisition & Signal Processing Controllers", + PCISubClass_11 + }, + { + 0x12, + L"Processing Accelerators", + PCISubClass_12 + }, + { + 0x13, + L"Non-Essential Instrumentation", + PCISubClass_13 + }, + { + 0xff, + L"Device does not fit in any defined classes", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +// +// Subclass strings entries +// +PCI_CLASS_ENTRY PCIBlankEntry[] = { + { + 0x00, + L"", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCISubClass_00[] = { + { + 0x00, + L"All devices other than VGA", + PCIBlankEntry + }, + { + 0x01, + L"VGA-compatible devices", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCISubClass_01[] = { + { + 0x00, + L"SCSI", + PCIPIFClass_0100 + }, + { + 0x01, + L"IDE controller", + PCIPIFClass_0101 + }, + { + 0x02, + L"Floppy disk controller", + PCIBlankEntry + }, + { + 0x03, + L"IPI controller", + PCIBlankEntry + }, + { + 0x04, + L"RAID controller", + PCIBlankEntry + }, + { + 0x05, + L"ATA controller with ADMA interface", + PCIPIFClass_0105 + }, + { + 0x06, + L"Serial ATA controller", + PCIPIFClass_0106 + }, + { + 0x07, + L"Serial Attached SCSI (SAS) controller ", + PCIPIFClass_0107 + }, + { + 0x08, + L"Non-volatile memory subsystem", + PCIPIFClass_0108 + }, + { + 0x09, + L"Universal Flash Storage (UFS) controller ", + PCIPIFClass_0109 + }, + { + 0x80, + L"Other mass storage controller", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCISubClass_02[] = { + { + 0x00, + L"Ethernet controller", + PCIBlankEntry + }, + { + 0x01, + L"Token ring controller", + PCIBlankEntry + }, + { + 0x02, + L"FDDI controller", + PCIBlankEntry + }, + { + 0x03, + L"ATM controller", + PCIBlankEntry + }, + { + 0x04, + L"ISDN controller", + PCIBlankEntry + }, + { + 0x05, + L"WorldFip controller", + PCIBlankEntry + }, + { + 0x06, + L"PICMG 2.14 Multi Computing", + PCIBlankEntry + }, + { + 0x07, + L"InfiniBand controller", + PCIBlankEntry + }, + { + 0x80, + L"Other network controller", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCISubClass_03[] = { + { + 0x00, + L"VGA/8514 controller", + PCIPIFClass_0300 + }, + { + 0x01, + L"XGA controller", + PCIBlankEntry + }, + { + 0x02, + L"3D controller", + PCIBlankEntry + }, + { + 0x80, + L"Other display controller", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */PCIBlankEntry + } +}; + +PCI_CLASS_ENTRY PCISubClass_04[] = { + { + 0x00, + L"Video device", + PCIBlankEntry + }, + { + 0x01, + L"Audio device", + PCIBlankEntry + }, + { + 0x02, + L"Computer Telephony device", + PCIBlankEntry + }, + { + 0x03, + L"Mixed mode device", + PCIBlankEntry + }, + { + 0x80, + L"Other multimedia device", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCISubClass_05[] = { + { + 0x00, + L"RAM memory controller", + PCIBlankEntry + }, + { + 0x01, + L"Flash memory controller", + PCIBlankEntry + }, + { + 0x80, + L"Other memory controller", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCISubClass_06[] = { + { + 0x00, + L"Host/PCI bridge", + PCIBlankEntry + }, + { + 0x01, + L"PCI/ISA bridge", + PCIBlankEntry + }, + { + 0x02, + L"PCI/EISA bridge", + PCIBlankEntry + }, + { + 0x03, + L"PCI/Micro Channel bridge", + PCIBlankEntry + }, + { + 0x04, + L"PCI/PCI bridge", + PCIPIFClass_0604 + }, + { + 0x05, + L"PCI/PCMCIA bridge", + PCIBlankEntry + }, + { + 0x06, + L"NuBus bridge", + PCIBlankEntry + }, + { + 0x07, + L"CardBus bridge", + PCIBlankEntry + }, + { + 0x08, + L"RACEway bridge", + PCIBlankEntry + }, + { + 0x09, + L"Semi-transparent PCI-to-PCI bridge", + PCIPIFClass_0609 + }, + { + 0x0A, + L"InfiniBand-to-PCI host bridge", + PCIBlankEntry + }, + { + 0x0B, + L"Advanced Switching to PCI host bridge", + PCIPIFClass_060b + }, + { + 0x80, + L"Other bridge type", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCISubClass_07[] = { + { + 0x00, + L"Serial controller", + PCIPIFClass_0700 + }, + { + 0x01, + L"Parallel port", + PCIPIFClass_0701 + }, + { + 0x02, + L"Multiport serial controller", + PCIBlankEntry + }, + { + 0x03, + L"Modem", + PCIPIFClass_0703 + }, + { + 0x04, + L"GPIB (IEEE 488.1/2) controller", + PCIBlankEntry + }, + { + 0x05, + L"Smart Card", + PCIBlankEntry + }, + { + 0x80, + L"Other communication device", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCISubClass_08[] = { + { + 0x00, + L"PIC", + PCIPIFClass_0800 + }, + { + 0x01, + L"DMA controller", + PCIPIFClass_0801 + }, + { + 0x02, + L"System timer", + PCIPIFClass_0802 + }, + { + 0x03, + L"RTC controller", + PCIPIFClass_0803 + }, + { + 0x04, + L"Generic PCI Hot-Plug controller", + PCIBlankEntry + }, + { + 0x05, + L"SD Host controller", + PCIBlankEntry + }, + { + 0x06, + L"IOMMU", + PCIBlankEntry + }, + { + 0x07, + L"Root Complex Event Collector", + PCIBlankEntry + }, + { + 0x80, + L"Other system peripheral", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCISubClass_09[] = { + { + 0x00, + L"Keyboard controller", + PCIBlankEntry + }, + { + 0x01, + L"Digitizer (pen)", + PCIBlankEntry + }, + { + 0x02, + L"Mouse controller", + PCIBlankEntry + }, + { + 0x03, + L"Scanner controller", + PCIBlankEntry + }, + { + 0x04, + L"Gameport controller", + PCIPIFClass_0904 + }, + { + 0x80, + L"Other input controller", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCISubClass_0a[] = { + { + 0x00, + L"Generic docking station", + PCIBlankEntry + }, + { + 0x80, + L"Other type of docking station", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCISubClass_0b[] = { + { + 0x00, + L"386", + PCIBlankEntry + }, + { + 0x01, + L"486", + PCIBlankEntry + }, + { + 0x02, + L"Pentium", + PCIBlankEntry + }, + { + 0x10, + L"Alpha", + PCIBlankEntry + }, + { + 0x20, + L"PowerPC", + PCIBlankEntry + }, + { + 0x30, + L"MIPS", + PCIBlankEntry + }, + { + 0x40, + L"Co-processor", + PCIBlankEntry + }, + { + 0x80, + L"Other processor", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCISubClass_0c[] = { + { + 0x00, + L"IEEE 1394", + PCIPIFClass_0c00 + }, + { + 0x01, + L"ACCESS.bus", + PCIBlankEntry + }, + { + 0x02, + L"SSA", + PCIBlankEntry + }, + { + 0x03, + L"USB", + PCIPIFClass_0c03 + }, + { + 0x04, + L"Fibre Channel", + PCIBlankEntry + }, + { + 0x05, + L"System Management Bus", + PCIBlankEntry + }, + { + 0x06, + L"InfiniBand", + PCIBlankEntry + }, + { + 0x07, + L"IPMI", + PCIPIFClass_0c07 + }, + { + 0x08, + L"SERCOS Interface Standard (IEC 61491)", + PCIBlankEntry + }, + { + 0x09, + L"CANbus", + PCIBlankEntry + }, + { + 0x80, + L"Other bus type", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCISubClass_0d[] = { + { + 0x00, + L"iRDA compatible controller", + PCIBlankEntry + }, + { + 0x01, + L"", + PCIPIFClass_0d01 + }, + { + 0x10, + L"RF controller", + PCIBlankEntry + }, + { + 0x11, + L"Bluetooth", + PCIBlankEntry + }, + { + 0x12, + L"Broadband", + PCIBlankEntry + }, + { + 0x20, + L"Ethernet (802.11a - 5 GHz)", + PCIBlankEntry + }, + { + 0x21, + L"Ethernet (802.11b - 2.4 GHz)", + PCIBlankEntry + }, + { + 0x80, + L"Other type of wireless controller", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCISubClass_0e[] = { + { + 0x00, + L"I2O Architecture", + PCIPIFClass_0e00 + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCISubClass_0f[] = { + { + 0x01, + L"TV", + PCIBlankEntry + }, + { + 0x02, + L"Audio", + PCIBlankEntry + }, + { + 0x03, + L"Voice", + PCIBlankEntry + }, + { + 0x04, + L"Data", + PCIBlankEntry + }, + { + 0x80, + L"Other satellite communication controller", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCISubClass_10[] = { + { + 0x00, + L"Network & computing Encrypt/Decrypt", + PCIBlankEntry + }, + { + 0x01, + L"Entertainment Encrypt/Decrypt", + PCIBlankEntry + }, + { + 0x80, + L"Other Encrypt/Decrypt", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCISubClass_11[] = { + { + 0x00, + L"DPIO modules", + PCIBlankEntry + }, + { + 0x01, + L"Performance Counters", + PCIBlankEntry + }, + { + 0x10, + L"Communications synchronization plus time and frequency test/measurement ", + PCIBlankEntry + }, + { + 0x20, + L"Management card", + PCIBlankEntry + }, + { + 0x80, + L"Other DAQ & SP controllers", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCISubClass_12[] = { + { + 0x00, + L"Processing Accelerator", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCISubClass_13[] = { + { + 0x00, + L"Non-Essential Instrumentation Function", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +// +// Programming Interface entries +// +PCI_CLASS_ENTRY PCIPIFClass_0100[] = { + { + 0x00, + L"SCSI controller", + PCIBlankEntry + }, + { + 0x11, + L"SCSI storage device SOP using PQI", + PCIBlankEntry + }, + { + 0x12, + L"SCSI controller SOP using PQI", + PCIBlankEntry + }, + { + 0x13, + L"SCSI storage device and controller SOP using PQI", + PCIBlankEntry + }, + { + 0x21, + L"SCSI storage device SOP using NVMe", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCIPIFClass_0101[] = { + { + 0x00, + L"", + PCIBlankEntry + }, + { + 0x01, + L"OM-primary", + PCIBlankEntry + }, + { + 0x02, + L"PI-primary", + PCIBlankEntry + }, + { + 0x03, + L"OM/PI-primary", + PCIBlankEntry + }, + { + 0x04, + L"OM-secondary", + PCIBlankEntry + }, + { + 0x05, + L"OM-primary, OM-secondary", + PCIBlankEntry + }, + { + 0x06, + L"PI-primary, OM-secondary", + PCIBlankEntry + }, + { + 0x07, + L"OM/PI-primary, OM-secondary", + PCIBlankEntry + }, + { + 0x08, + L"OM-secondary", + PCIBlankEntry + }, + { + 0x09, + L"OM-primary, PI-secondary", + PCIBlankEntry + }, + { + 0x0a, + L"PI-primary, PI-secondary", + PCIBlankEntry + }, + { + 0x0b, + L"OM/PI-primary, PI-secondary", + PCIBlankEntry + }, + { + 0x0c, + L"OM-secondary", + PCIBlankEntry + }, + { + 0x0d, + L"OM-primary, OM/PI-secondary", + PCIBlankEntry + }, + { + 0x0e, + L"PI-primary, OM/PI-secondary", + PCIBlankEntry + }, + { + 0x0f, + L"OM/PI-primary, OM/PI-secondary", + PCIBlankEntry + }, + { + 0x80, + L"Master", + PCIBlankEntry + }, + { + 0x81, + L"Master, OM-primary", + PCIBlankEntry + }, + { + 0x82, + L"Master, PI-primary", + PCIBlankEntry + }, + { + 0x83, + L"Master, OM/PI-primary", + PCIBlankEntry + }, + { + 0x84, + L"Master, OM-secondary", + PCIBlankEntry + }, + { + 0x85, + L"Master, OM-primary, OM-secondary", + PCIBlankEntry + }, + { + 0x86, + L"Master, PI-primary, OM-secondary", + PCIBlankEntry + }, + { + 0x87, + L"Master, OM/PI-primary, OM-secondary", + PCIBlankEntry + }, + { + 0x88, + L"Master, OM-secondary", + PCIBlankEntry + }, + { + 0x89, + L"Master, OM-primary, PI-secondary", + PCIBlankEntry + }, + { + 0x8a, + L"Master, PI-primary, PI-secondary", + PCIBlankEntry + }, + { + 0x8b, + L"Master, OM/PI-primary, PI-secondary", + PCIBlankEntry + }, + { + 0x8c, + L"Master, OM-secondary", + PCIBlankEntry + }, + { + 0x8d, + L"Master, OM-primary, OM/PI-secondary", + PCIBlankEntry + }, + { + 0x8e, + L"Master, PI-primary, OM/PI-secondary", + PCIBlankEntry + }, + { + 0x8f, + L"Master, OM/PI-primary, OM/PI-secondary", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCIPIFClass_0105[] = { + { + 0x20, + L"Single stepping", + PCIBlankEntry + }, + { + 0x30, + L"Continuous operation", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCIPIFClass_0106[] = { + { + 0x00, + L"", + PCIBlankEntry + }, + { + 0x01, + L"AHCI", + PCIBlankEntry + }, + { + 0x02, + L"Serial Storage Bus", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCIPIFClass_0107[] = { + { + 0x00, + L"", + PCIBlankEntry + }, + { + 0x01, + L"Obsolete", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCIPIFClass_0108[] = { + { + 0x00, + L"", + PCIBlankEntry + }, + { + 0x01, + L"NVMHCI", + PCIBlankEntry + }, + { + 0x02, + L"NVM Express", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCIPIFClass_0109[] = { + { + 0x00, + L"", + PCIBlankEntry + }, + { + 0x01, + L"UFSHCI", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCIPIFClass_0300[] = { + { + 0x00, + L"VGA compatible", + PCIBlankEntry + }, + { + 0x01, + L"8514 compatible", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCIPIFClass_0604[] = { + { + 0x00, + L"", + PCIBlankEntry + }, + { + 0x01, + L"Subtractive decode", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCIPIFClass_0609[] = { + { + 0x40, + L"Primary PCI bus side facing the system host processor", + PCIBlankEntry + }, + { + 0x80, + L"Secondary PCI bus side facing the system host processor", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCIPIFClass_060b[] = { + { + 0x00, + L"Custom", + PCIBlankEntry + }, + { + 0x01, + L"ASI-SIG Defined Portal", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCIPIFClass_0700[] = { + { + 0x00, + L"Generic XT-compatible", + PCIBlankEntry + }, + { + 0x01, + L"16450-compatible", + PCIBlankEntry + }, + { + 0x02, + L"16550-compatible", + PCIBlankEntry + }, + { + 0x03, + L"16650-compatible", + PCIBlankEntry + }, + { + 0x04, + L"16750-compatible", + PCIBlankEntry + }, + { + 0x05, + L"16850-compatible", + PCIBlankEntry + }, + { + 0x06, + L"16950-compatible", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCIPIFClass_0701[] = { + { + 0x00, + L"", + PCIBlankEntry + }, + { + 0x01, + L"Bi-directional", + PCIBlankEntry + }, + { + 0x02, + L"ECP 1.X-compliant", + PCIBlankEntry + }, + { + 0x03, + L"IEEE 1284", + PCIBlankEntry + }, + { + 0xfe, + L"IEEE 1284 target (not a controller)", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCIPIFClass_0703[] = { + { + 0x00, + L"Generic", + PCIBlankEntry + }, + { + 0x01, + L"Hayes-compatible 16450", + PCIBlankEntry + }, + { + 0x02, + L"Hayes-compatible 16550", + PCIBlankEntry + }, + { + 0x03, + L"Hayes-compatible 16650", + PCIBlankEntry + }, + { + 0x04, + L"Hayes-compatible 16750", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCIPIFClass_0800[] = { + { + 0x00, + L"Generic 8259", + PCIBlankEntry + }, + { + 0x01, + L"ISA", + PCIBlankEntry + }, + { + 0x02, + L"EISA", + PCIBlankEntry + }, + { + 0x10, + L"IO APIC", + PCIBlankEntry + }, + { + 0x20, + L"IO(x) APIC interrupt controller", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCIPIFClass_0801[] = { + { + 0x00, + L"Generic 8237", + PCIBlankEntry + }, + { + 0x01, + L"ISA", + PCIBlankEntry + }, + { + 0x02, + L"EISA", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCIPIFClass_0802[] = { + { + 0x00, + L"Generic 8254", + PCIBlankEntry + }, + { + 0x01, + L"ISA", + PCIBlankEntry + }, + { + 0x02, + L"EISA", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCIPIFClass_0803[] = { + { + 0x00, + L"Generic", + PCIBlankEntry + }, + { + 0x01, + L"ISA", + PCIBlankEntry + }, + { + 0x02, + L"EISA", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCIPIFClass_0904[] = { + { + 0x00, + L"Generic", + PCIBlankEntry + }, + { + 0x10, + L"", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCIPIFClass_0c00[] = { + { + 0x00, + L"", + PCIBlankEntry + }, + { + 0x10, + L"Using 1394 OpenHCI spec", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCIPIFClass_0c03[] = { + { + 0x00, + L"UHCI", + PCIBlankEntry + }, + { + 0x10, + L"OHCI", + PCIBlankEntry + }, + { + 0x20, + L"EHCI", + PCIBlankEntry + }, + { + 0x30, + L"xHCI", + PCIBlankEntry + }, + { + 0x80, + L"No specific programming interface", + PCIBlankEntry + }, + { + 0xfe, + L"(Not Host Controller)", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCIPIFClass_0c07[] = { + { + 0x00, + L"SMIC", + PCIBlankEntry + }, + { + 0x01, + L"Keyboard Controller Style", + PCIBlankEntry + }, + { + 0x02, + L"Block Transfer", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCIPIFClass_0d01[] = { + { + 0x00, + L"Consumer IR controller", + PCIBlankEntry + }, + { + 0x10, + L"UWB Radio controller", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + +PCI_CLASS_ENTRY PCIPIFClass_0e00[] = { + { + 0x00, + L"Message FIFO at offset 40h", + PCIBlankEntry + }, + { + 0x01, + L"", + PCIBlankEntry + }, + { + 0x00, + NULL, + /* null string ends the list */NULL + } +}; + + +/** + Generates printable Unicode strings that represent PCI device class, + subclass and programmed I/F based on a value passed to the function. + + @param[in] ClassCode Value representing the PCI "Class Code" register read from a + PCI device. The encodings are: + bits 23:16 - Base Class Code + bits 15:8 - Sub-Class Code + bits 7:0 - Programming Interface + @param[in, out] ClassStrings Pointer of PCI_CLASS_STRINGS structure, which contains + printable class strings corresponding to ClassCode. The + caller must not modify the strings that are pointed by + the fields in ClassStrings. +**/ +VOID +PciGetClassStrings ( + IN UINT32 ClassCode, + IN OUT PCI_CLASS_STRINGS *ClassStrings + ) +{ + INTN Index; + UINT8 Code; + PCI_CLASS_ENTRY *CurrentClass; + + // + // Assume no strings found + // + ClassStrings->BaseClass = L"UNDEFINED"; + ClassStrings->SubClass = L"UNDEFINED"; + ClassStrings->PIFClass = L"UNDEFINED"; + + CurrentClass = gClassStringList; + Code = (UINT8) (ClassCode >> 16); + Index = 0; + + // + // Go through all entries of the base class, until the entry with a matching + // base class code is found. If reaches an entry with a null description + // text, the last entry is met, which means no text for the base class was + // found, so no more action is needed. + // + while (Code != CurrentClass[Index].Code) { + if (NULL == CurrentClass[Index].DescText) { + return ; + } + + Index++; + } + // + // A base class was found. Assign description, and check if this class has + // sub-class defined. If sub-class defined, no more action is needed, + // otherwise, continue to find description for the sub-class code. + // + ClassStrings->BaseClass = CurrentClass[Index].DescText; + if (NULL == CurrentClass[Index].LowerLevelClass) { + return ; + } + // + // find Subclass entry + // + CurrentClass = CurrentClass[Index].LowerLevelClass; + Code = (UINT8) (ClassCode >> 8); + Index = 0; + + // + // Go through all entries of the sub-class, until the entry with a matching + // sub-class code is found. If reaches an entry with a null description + // text, the last entry is met, which means no text for the sub-class was + // found, so no more action is needed. + // + while (Code != CurrentClass[Index].Code) { + if (NULL == CurrentClass[Index].DescText) { + return ; + } + + Index++; + } + // + // A class was found for the sub-class code. Assign description, and check if + // this sub-class has programming interface defined. If no, no more action is + // needed, otherwise, continue to find description for the programming + // interface. + // + ClassStrings->SubClass = CurrentClass[Index].DescText; + if (NULL == CurrentClass[Index].LowerLevelClass) { + return ; + } + // + // Find programming interface entry + // + CurrentClass = CurrentClass[Index].LowerLevelClass; + Code = (UINT8) ClassCode; + Index = 0; + + // + // Go through all entries of the I/F entries, until the entry with a + // matching I/F code is found. If reaches an entry with a null description + // text, the last entry is met, which means no text was found, so no more + // action is needed. + // + while (Code != CurrentClass[Index].Code) { + if (NULL == CurrentClass[Index].DescText) { + return ; + } + + Index++; + } + // + // A class was found for the I/F code. Assign description, done! + // + ClassStrings->PIFClass = CurrentClass[Index].DescText; + return ; +} + +/** + Print strings that represent PCI device class, subclass and programmed I/F. + + @param[in] ClassCodePtr Points to the memory which stores register Class Code in PCI + configuration space. + @param[in] IncludePIF If the printed string should include the programming I/F part +**/ +VOID +PciPrintClassCode ( + IN UINT8 *ClassCodePtr, + IN BOOLEAN IncludePIF + ) +{ + UINT32 ClassCode; + PCI_CLASS_STRINGS ClassStrings; + + ClassCode = 0; + ClassCode |= (UINT32)ClassCodePtr[0]; + ClassCode |= (UINT32)(ClassCodePtr[1] << 8); + ClassCode |= (UINT32)(ClassCodePtr[2] << 16); + + // + // Get name from class code + // + PciGetClassStrings (ClassCode, &ClassStrings); + + if (IncludePIF) { + // + // Print base class, sub class, and programming inferface name + // + ShellPrintEx (-1, -1, L"%s - %s - %s", + ClassStrings.BaseClass, + ClassStrings.SubClass, + ClassStrings.PIFClass + ); + + } else { + // + // Only print base class and sub class name + // + ShellPrintEx (-1, -1, L"%s - %s", + ClassStrings.BaseClass, + ClassStrings.SubClass + ); + } +} + +/** + This function finds out the protocol which is in charge of the given + segment, and its bus range covers the current bus number. It lookes + each instances of RootBridgeIoProtocol handle, until the one meets the + criteria is found. + + @param[in] HandleBuf Buffer which holds all PCI_ROOT_BRIDIGE_IO_PROTOCOL handles. + @param[in] HandleCount Count of all PCI_ROOT_BRIDIGE_IO_PROTOCOL handles. + @param[in] Segment Segment number of device we are dealing with. + @param[in] Bus Bus number of device we are dealing with. + @param[out] IoDev Handle used to access configuration space of PCI device. + + @retval EFI_SUCCESS The command completed successfully. + @retval EFI_INVALID_PARAMETER Invalid parameter. + +**/ +EFI_STATUS +PciFindProtocolInterface ( + IN EFI_HANDLE *HandleBuf, + IN UINTN HandleCount, + IN UINT16 Segment, + IN UINT16 Bus, + OUT EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL **IoDev + ); + +/** + This function gets the protocol interface from the given handle, and + obtains its address space descriptors. + + @param[in] Handle The PCI_ROOT_BRIDIGE_IO_PROTOCOL handle. + @param[out] IoDev Handle used to access configuration space of PCI device. + @param[out] Descriptors Points to the address space descriptors. + + @retval EFI_SUCCESS The command completed successfully +**/ +EFI_STATUS +PciGetProtocolAndResource ( + IN EFI_HANDLE Handle, + OUT EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL **IoDev, + OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors + ); + +/** + This function get the next bus range of given address space descriptors. + It also moves the pointer backward a node, to get prepared to be called + again. + + @param[in, out] Descriptors Points to current position of a serial of address space + descriptors. + @param[out] MinBus The lower range of bus number. + @param[out] MaxBus The upper range of bus number. + @param[out] IsEnd Meet end of the serial of descriptors. + + @retval EFI_SUCCESS The command completed successfully. +**/ +EFI_STATUS +PciGetNextBusRange ( + IN OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors, + OUT UINT16 *MinBus, + OUT UINT16 *MaxBus, + OUT BOOLEAN *IsEnd + ); + +/** + Explain the data in PCI configuration space. The part which is common for + PCI device and bridge is interpreted in this function. It calls other + functions to interpret data unique for device or bridge. + + @param[in] ConfigSpace Data in PCI configuration space. + @param[in] Address Address used to access configuration space of this PCI device. + @param[in] IoDev Handle used to access configuration space of PCI device. +**/ +VOID +PciExplainPci ( + IN PCI_CONFIG_SPACE *ConfigSpace, + IN UINT64 Address, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev + ); + +/** + Explain the device specific part of data in PCI configuration space. + + @param[in] Device Data in PCI configuration space. + @param[in] Address Address used to access configuration space of this PCI device. + @param[in] IoDev Handle used to access configuration space of PCI device. + + @retval EFI_SUCCESS The command completed successfully. +**/ +EFI_STATUS +PciExplainDeviceData ( + IN PCI_DEVICE_HEADER_TYPE_REGION *Device, + IN UINT64 Address, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev + ); + +/** + Explain the bridge specific part of data in PCI configuration space. + + @param[in] Bridge Bridge specific data region in PCI configuration space. + @param[in] Address Address used to access configuration space of this PCI device. + @param[in] IoDev Handle used to access configuration space of PCI device. + + @retval EFI_SUCCESS The command completed successfully. +**/ +EFI_STATUS +PciExplainBridgeData ( + IN PCI_BRIDGE_CONTROL_REGISTER *Bridge, + IN UINT64 Address, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev + ); + +/** + Explain the Base Address Register(Bar) in PCI configuration space. + + @param[in] Bar Points to the Base Address Register intended to interpret. + @param[in] Command Points to the register Command. + @param[in] Address Address used to access configuration space of this PCI device. + @param[in] IoDev Handle used to access configuration space of PCI device. + @param[in, out] Index The Index. + + @retval EFI_SUCCESS The command completed successfully. +**/ +EFI_STATUS +PciExplainBar ( + IN UINT32 *Bar, + IN UINT16 *Command, + IN UINT64 Address, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, + IN OUT UINTN *Index + ); + +/** + Explain the cardbus specific part of data in PCI configuration space. + + @param[in] CardBus CardBus specific region of PCI configuration space. + @param[in] Address Address used to access configuration space of this PCI device. + @param[in] IoDev Handle used to access configuration space of PCI device. + + @retval EFI_SUCCESS The command completed successfully. +**/ +EFI_STATUS +PciExplainCardBusData ( + IN PCI_CARDBUS_CONTROL_REGISTER *CardBus, + IN UINT64 Address, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev + ); + +/** + Explain each meaningful bit of register Status. The definition of Status is + slightly different depending on the PCI header type. + + @param[in] Status Points to the content of register Status. + @param[in] MainStatus Indicates if this register is main status(not secondary + status). + @param[in] HeaderType Header type of this PCI device. + + @retval EFI_SUCCESS The command completed successfully. +**/ +EFI_STATUS +PciExplainStatus ( + IN UINT16 *Status, + IN BOOLEAN MainStatus, + IN PCI_HEADER_TYPE HeaderType + ); + +/** + Explain each meaningful bit of register Command. + + @param[in] Command Points to the content of register Command. + + @retval EFI_SUCCESS The command completed successfully. +**/ +EFI_STATUS +PciExplainCommand ( + IN UINT16 *Command + ); + +/** + Explain each meaningful bit of register Bridge Control. + + @param[in] BridgeControl Points to the content of register Bridge Control. + @param[in] HeaderType The headertype. + + @retval EFI_SUCCESS The command completed successfully. +**/ +EFI_STATUS +PciExplainBridgeControl ( + IN UINT16 *BridgeControl, + IN PCI_HEADER_TYPE HeaderType + ); + +/** + Locate capability register block per capability ID. + + @param[in] ConfigSpace Data in PCI configuration space. + @param[in] CapabilityId The capability ID. + + @return The offset of the register block per capability ID. +**/ +UINT8 +LocatePciCapability ( + IN PCI_CONFIG_SPACE *ConfigSpace, + IN UINT8 CapabilityId + ); + +/** + Display Pcie device structure. + + @param[in] PciExpressCap PCI Express capability buffer. + @param[in] ExtendedConfigSpace PCI Express extended configuration space. + @param[in] ExtendedConfigSize PCI Express extended configuration size. + @param[in] ExtendedCapability PCI Express extended capability ID to explain. +**/ +VOID +PciExplainPciExpress ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap, + IN UINT8 *ExtendedConfigSpace, + IN UINTN ExtendedConfigSize, + IN CONST UINT16 ExtendedCapability + ); + +/** + Print out information of the capability information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieCapReg ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ); + +/** + Print out information of the device capability information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieDeviceCap ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ); + +/** + Print out information of the device control information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieDeviceControl ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ); + +/** + Print out information of the device status information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieDeviceStatus ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ); + +/** + Print out information of the device link information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieLinkCap ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ); + +/** + Print out information of the device link control information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieLinkControl ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ); + +/** + Print out information of the device link status information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieLinkStatus ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ); + +/** + Print out information of the device slot information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieSlotCap ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ); + +/** + Print out information of the device slot control information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieSlotControl ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ); + +/** + Print out information of the device slot status information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieSlotStatus ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ); + +/** + Print out information of the device root information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieRootControl ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ); + +/** + Print out information of the device root capability information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieRootCap ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ); + +/** + Print out information of the device root status information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieRootStatus ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ); + +typedef EFI_STATUS (*PCIE_EXPLAIN_FUNCTION) (IN PCI_CAPABILITY_PCIEXP *PciExpressCap); + +typedef enum { + FieldWidthUINT8, + FieldWidthUINT16, + FieldWidthUINT32 +} PCIE_CAPREG_FIELD_WIDTH; + +typedef enum { + PcieExplainTypeCommon, + PcieExplainTypeDevice, + PcieExplainTypeLink, + PcieExplainTypeSlot, + PcieExplainTypeRoot, + PcieExplainTypeMax +} PCIE_EXPLAIN_TYPE; + +typedef struct +{ + UINT16 Token; + UINTN Offset; + PCIE_CAPREG_FIELD_WIDTH Width; + PCIE_EXPLAIN_FUNCTION Func; + PCIE_EXPLAIN_TYPE Type; +} PCIE_EXPLAIN_STRUCT; + +PCIE_EXPLAIN_STRUCT PcieExplainList[] = { + { + STRING_TOKEN (STR_PCIEX_CAPABILITY_CAPID), + 0x00, + FieldWidthUINT8, + NULL, + PcieExplainTypeCommon + }, + { + STRING_TOKEN (STR_PCIEX_NEXTCAP_PTR), + 0x01, + FieldWidthUINT8, + NULL, + PcieExplainTypeCommon + }, + { + STRING_TOKEN (STR_PCIEX_CAP_REGISTER), + 0x02, + FieldWidthUINT16, + ExplainPcieCapReg, + PcieExplainTypeCommon + }, + { + STRING_TOKEN (STR_PCIEX_DEVICE_CAP), + 0x04, + FieldWidthUINT32, + ExplainPcieDeviceCap, + PcieExplainTypeDevice + }, + { + STRING_TOKEN (STR_PCIEX_DEVICE_CONTROL), + 0x08, + FieldWidthUINT16, + ExplainPcieDeviceControl, + PcieExplainTypeDevice + }, + { + STRING_TOKEN (STR_PCIEX_DEVICE_STATUS), + 0x0a, + FieldWidthUINT16, + ExplainPcieDeviceStatus, + PcieExplainTypeDevice + }, + { + STRING_TOKEN (STR_PCIEX_LINK_CAPABILITIES), + 0x0c, + FieldWidthUINT32, + ExplainPcieLinkCap, + PcieExplainTypeLink + }, + { + STRING_TOKEN (STR_PCIEX_LINK_CONTROL), + 0x10, + FieldWidthUINT16, + ExplainPcieLinkControl, + PcieExplainTypeLink + }, + { + STRING_TOKEN (STR_PCIEX_LINK_STATUS), + 0x12, + FieldWidthUINT16, + ExplainPcieLinkStatus, + PcieExplainTypeLink + }, + { + STRING_TOKEN (STR_PCIEX_SLOT_CAPABILITIES), + 0x14, + FieldWidthUINT32, + ExplainPcieSlotCap, + PcieExplainTypeSlot + }, + { + STRING_TOKEN (STR_PCIEX_SLOT_CONTROL), + 0x18, + FieldWidthUINT16, + ExplainPcieSlotControl, + PcieExplainTypeSlot + }, + { + STRING_TOKEN (STR_PCIEX_SLOT_STATUS), + 0x1a, + FieldWidthUINT16, + ExplainPcieSlotStatus, + PcieExplainTypeSlot + }, + { + STRING_TOKEN (STR_PCIEX_ROOT_CONTROL), + 0x1c, + FieldWidthUINT16, + ExplainPcieRootControl, + PcieExplainTypeRoot + }, + { + STRING_TOKEN (STR_PCIEX_RSVDP), + 0x1e, + FieldWidthUINT16, + ExplainPcieRootCap, + PcieExplainTypeRoot + }, + { + STRING_TOKEN (STR_PCIEX_ROOT_STATUS), + 0x20, + FieldWidthUINT32, + ExplainPcieRootStatus, + PcieExplainTypeRoot + }, + { + 0, + 0, + (PCIE_CAPREG_FIELD_WIDTH)0, + NULL, + PcieExplainTypeMax + } +}; + +// +// Global Variables +// +PCI_CONFIG_SPACE *mConfigSpace = NULL; +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-s", TypeValue}, + {L"-i", TypeFlag}, + {L"-ec", TypeValue}, + {NULL, TypeMax} + }; + +CHAR16 *DevicePortTypeTable[] = { + L"PCI Express Endpoint", + L"Legacy PCI Express Endpoint", + L"Unknown Type", + L"Unknonw Type", + L"Root Port of PCI Express Root Complex", + L"Upstream Port of PCI Express Switch", + L"Downstream Port of PCI Express Switch", + L"PCI Express to PCI/PCI-X Bridge", + L"PCI/PCI-X to PCI Express Bridge", + L"Root Complex Integrated Endpoint", + L"Root Complex Event Collector" +}; + +CHAR16 *L0sLatencyStrTable[] = { + L"Less than 64ns", + L"64ns to less than 128ns", + L"128ns to less than 256ns", + L"256ns to less than 512ns", + L"512ns to less than 1us", + L"1us to less than 2us", + L"2us-4us", + L"More than 4us" +}; + +CHAR16 *L1LatencyStrTable[] = { + L"Less than 1us", + L"1us to less than 2us", + L"2us to less than 4us", + L"4us to less than 8us", + L"8us to less than 16us", + L"16us to less than 32us", + L"32us-64us", + L"More than 64us" +}; + +CHAR16 *ASPMCtrlStrTable[] = { + L"Disabled", + L"L0s Entry Enabled", + L"L1 Entry Enabled", + L"L0s and L1 Entry Enabled" +}; + +CHAR16 *SlotPwrLmtScaleTable[] = { + L"1.0x", + L"0.1x", + L"0.01x", + L"0.001x" +}; + +CHAR16 *IndicatorTable[] = { + L"Reserved", + L"On", + L"Blink", + L"Off" +}; + + +/** + Function for 'pci' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunPci ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + UINT16 Segment; + UINT16 Bus; + UINT16 Device; + UINT16 Func; + UINT64 Address; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev; + EFI_STATUS Status; + PCI_DEVICE_INDEPENDENT_REGION PciHeader; + PCI_CONFIG_SPACE ConfigSpace; + UINTN ScreenCount; + UINTN TempColumn; + UINTN ScreenSize; + BOOLEAN ExplainData; + UINTN Index; + UINTN SizeOfHeader; + BOOLEAN PrintTitle; + UINTN HandleBufSize; + EFI_HANDLE *HandleBuf; + UINTN HandleCount; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors; + UINT16 MinBus; + UINT16 MaxBus; + BOOLEAN IsEnd; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CONST CHAR16 *Temp; + UINT64 RetVal; + UINT16 ExtendedCapability; + UINT8 PcieCapabilityPtr; + UINT8 *ExtendedConfigSpace; + UINTN ExtendedConfigSize; + + ShellStatus = SHELL_SUCCESS; + Status = EFI_SUCCESS; + Address = 0; + IoDev = NULL; + HandleBuf = NULL; + Package = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"pci", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + + if (ShellCommandLineGetCount(Package) == 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"pci"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + + if (ShellCommandLineGetCount(Package) > 4) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"pci"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + if (ShellCommandLineGetFlag(Package, L"-ec") && ShellCommandLineGetValue(Package, L"-ec") == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDebug1HiiHandle, L"pci", L"-ec"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + if (ShellCommandLineGetFlag(Package, L"-s") && ShellCommandLineGetValue(Package, L"-s") == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDebug1HiiHandle, L"pci", L"-s"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + // + // Get all instances of PciRootBridgeIo. Allocate space for 1 EFI_HANDLE and + // call LibLocateHandle(), if EFI_BUFFER_TOO_SMALL is returned, allocate enough + // space for handles and call it again. + // + HandleBufSize = sizeof (EFI_HANDLE); + HandleBuf = (EFI_HANDLE *) AllocateZeroPool (HandleBufSize); + if (HandleBuf == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellDebug1HiiHandle, L"pci"); + ShellStatus = SHELL_OUT_OF_RESOURCES; + goto Done; + } + + Status = gBS->LocateHandle ( + ByProtocol, + &gEfiPciRootBridgeIoProtocolGuid, + NULL, + &HandleBufSize, + HandleBuf + ); + + if (Status == EFI_BUFFER_TOO_SMALL) { + HandleBuf = ReallocatePool (sizeof (EFI_HANDLE), HandleBufSize, HandleBuf); + if (HandleBuf == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellDebug1HiiHandle, L"pci"); + ShellStatus = SHELL_OUT_OF_RESOURCES; + goto Done; + } + + Status = gBS->LocateHandle ( + ByProtocol, + &gEfiPciRootBridgeIoProtocolGuid, + NULL, + &HandleBufSize, + HandleBuf + ); + } + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PCIRBIO_NF), gShellDebug1HiiHandle, L"pci"); + ShellStatus = SHELL_NOT_FOUND; + goto Done; + } + + HandleCount = HandleBufSize / sizeof (EFI_HANDLE); + // + // Argument Count == 1(no other argument): enumerate all pci functions + // + if (ShellCommandLineGetCount(Package) == 1) { + gST->ConOut->QueryMode ( + gST->ConOut, + gST->ConOut->Mode->Mode, + &TempColumn, + &ScreenSize + ); + + ScreenCount = 0; + ScreenSize -= 4; + if ((ScreenSize & 1) == 1) { + ScreenSize -= 1; + } + + PrintTitle = TRUE; + + // + // For each handle, which decides a segment and a bus number range, + // enumerate all devices on it. + // + for (Index = 0; Index < HandleCount; Index++) { + Status = PciGetProtocolAndResource ( + HandleBuf[Index], + &IoDev, + &Descriptors + ); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_PCI_HANDLE_CFG_ERR), gShellDebug1HiiHandle, L"pci"); + ShellStatus = SHELL_NOT_FOUND; + goto Done; + } + // + // No document say it's impossible for a RootBridgeIo protocol handle + // to have more than one address space descriptors, so find out every + // bus range and for each of them do device enumeration. + // + while (TRUE) { + Status = PciGetNextBusRange (&Descriptors, &MinBus, &MaxBus, &IsEnd); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_PCI_BUS_RANGE_ERR), gShellDebug1HiiHandle, L"pci"); + ShellStatus = SHELL_NOT_FOUND; + goto Done; + } + + if (IsEnd) { + break; + } + + for (Bus = MinBus; Bus <= MaxBus; Bus++) { + // + // For each devices, enumerate all functions it contains + // + for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) { + // + // For each function, read its configuration space and print summary + // + for (Func = 0; Func <= PCI_MAX_FUNC; Func++) { + if (ShellGetExecutionBreakFlag ()) { + ShellStatus = SHELL_ABORTED; + goto Done; + } + Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0); + IoDev->Pci.Read ( + IoDev, + EfiPciWidthUint16, + Address, + 1, + &PciHeader.VendorId + ); + + // + // If VendorId = 0xffff, there does not exist a device at this + // location. For each device, if there is any function on it, + // there must be 1 function at Function 0. So if Func = 0, there + // will be no more functions in the same device, so we can break + // loop to deal with the next device. + // + if (PciHeader.VendorId == 0xffff && Func == 0) { + break; + } + + if (PciHeader.VendorId != 0xffff) { + + if (PrintTitle) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_PCI_TITLE), gShellDebug1HiiHandle); + PrintTitle = FALSE; + } + + IoDev->Pci.Read ( + IoDev, + EfiPciWidthUint32, + Address, + sizeof (PciHeader) / sizeof (UINT32), + &PciHeader + ); + + ShellPrintHiiEx( + -1, -1, NULL, STRING_TOKEN (STR_PCI_LINE_P1), gShellDebug1HiiHandle, + IoDev->SegmentNumber, + Bus, + Device, + Func + ); + + PciPrintClassCode (PciHeader.ClassCode, FALSE); + ShellPrintHiiEx( + -1, -1, NULL, STRING_TOKEN (STR_PCI_LINE_P2), gShellDebug1HiiHandle, + PciHeader.VendorId, + PciHeader.DeviceId, + PciHeader.ClassCode[0] + ); + + ScreenCount += 2; + if (ScreenCount >= ScreenSize && ScreenSize != 0) { + // + // If ScreenSize == 0 we have the console redirected so don't + // block updates + // + ScreenCount = 0; + } + // + // If this is not a multi-function device, we can leave the loop + // to deal with the next device. + // + if (Func == 0 && ((PciHeader.HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00)) { + break; + } + } + } + } + } + // + // If Descriptor is NULL, Configuration() returns EFI_UNSUPPRORED, + // we assume the bus range is 0~PCI_MAX_BUS. After enumerated all + // devices on all bus, we can leave loop. + // + if (Descriptors == NULL) { + break; + } + } + } + + Status = EFI_SUCCESS; + goto Done; + } + + ExplainData = FALSE; + Segment = 0; + Bus = 0; + Device = 0; + Func = 0; + ExtendedCapability = 0xFFFF; + if (ShellCommandLineGetFlag(Package, L"-i")) { + ExplainData = TRUE; + } + + Temp = ShellCommandLineGetValue(Package, L"-s"); + if (Temp != NULL) { + // + // Input converted to hexadecimal number. + // + if (!EFI_ERROR (ShellConvertStringToUint64 (Temp, &RetVal, TRUE, TRUE))) { + Segment = (UINT16) RetVal; + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV_HEX), gShellDebug1HiiHandle, L"pci", Temp); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + } + + // + // The first Argument(except "-i") is assumed to be Bus number, second + // to be Device number, and third to be Func number. + // + Temp = ShellCommandLineGetRawValue(Package, 1); + if (Temp != NULL) { + // + // Input converted to hexadecimal number. + // + if (!EFI_ERROR (ShellConvertStringToUint64 (Temp, &RetVal, TRUE, TRUE))) { + Bus = (UINT16) RetVal; + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV_HEX), gShellDebug1HiiHandle, L"pci", Temp); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + + if (Bus > PCI_MAX_BUS) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"pci", Temp); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + } + Temp = ShellCommandLineGetRawValue(Package, 2); + if (Temp != NULL) { + // + // Input converted to hexadecimal number. + // + if (!EFI_ERROR (ShellConvertStringToUint64 (Temp, &RetVal, TRUE, TRUE))) { + Device = (UINT16) RetVal; + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV_HEX), gShellDebug1HiiHandle, L"pci", Temp); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + + if (Device > PCI_MAX_DEVICE){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"pci", Temp); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + } + + Temp = ShellCommandLineGetRawValue(Package, 3); + if (Temp != NULL) { + // + // Input converted to hexadecimal number. + // + if (!EFI_ERROR (ShellConvertStringToUint64 (Temp, &RetVal, TRUE, TRUE))) { + Func = (UINT16) RetVal; + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV_HEX), gShellDebug1HiiHandle, L"pci", Temp); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + + if (Func > PCI_MAX_FUNC){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"pci", Temp); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + } + + Temp = ShellCommandLineGetValue (Package, L"-ec"); + if (Temp != NULL) { + // + // Input converted to hexadecimal number. + // + if (!EFI_ERROR (ShellConvertStringToUint64 (Temp, &RetVal, TRUE, TRUE))) { + ExtendedCapability = (UINT16) RetVal; + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV_HEX), gShellDebug1HiiHandle, L"pci", Temp); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + } + + // + // Find the protocol interface who's in charge of current segment, and its + // bus range covers the current bus + // + Status = PciFindProtocolInterface ( + HandleBuf, + HandleCount, + Segment, + Bus, + &IoDev + ); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx( + -1, -1, NULL, STRING_TOKEN (STR_PCI_NO_FIND), gShellDebug1HiiHandle, L"pci", + Segment, + Bus + ); + ShellStatus = SHELL_NOT_FOUND; + goto Done; + } + + Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0); + Status = IoDev->Pci.Read ( + IoDev, + EfiPciWidthUint8, + Address, + sizeof (ConfigSpace), + &ConfigSpace + ); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_PCI_NO_CFG), gShellDebug1HiiHandle, L"pci"); + ShellStatus = SHELL_ACCESS_DENIED; + goto Done; + } + + mConfigSpace = &ConfigSpace; + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_PCI_INFO), + gShellDebug1HiiHandle, + Segment, + Bus, + Device, + Func, + Segment, + Bus, + Device, + Func + ); + + // + // Dump standard header of configuration space + // + SizeOfHeader = sizeof (ConfigSpace.Common) + sizeof (ConfigSpace.NonCommon); + + DumpHex (2, 0, SizeOfHeader, &ConfigSpace); + ShellPrintEx(-1,-1, L"\r\n"); + + // + // Dump device dependent Part of configuration space + // + DumpHex ( + 2, + SizeOfHeader, + sizeof (ConfigSpace) - SizeOfHeader, + ConfigSpace.Data + ); + + ExtendedConfigSpace = NULL; + ExtendedConfigSize = 0; + PcieCapabilityPtr = LocatePciCapability (&ConfigSpace, EFI_PCI_CAPABILITY_ID_PCIEXP); + if (PcieCapabilityPtr != 0) { + ExtendedConfigSize = 0x1000 - EFI_PCIE_CAPABILITY_BASE_OFFSET; + ExtendedConfigSpace = AllocatePool (ExtendedConfigSize); + if (ExtendedConfigSpace != NULL) { + Status = IoDev->Pci.Read ( + IoDev, + EfiPciWidthUint32, + EFI_PCI_ADDRESS (Bus, Device, Func, EFI_PCIE_CAPABILITY_BASE_OFFSET), + ExtendedConfigSize / sizeof (UINT32), + ExtendedConfigSpace + ); + if (EFI_ERROR (Status)) { + SHELL_FREE_NON_NULL (ExtendedConfigSpace); + } + } + } + + if ((ExtendedConfigSpace != NULL) && !ShellGetExecutionBreakFlag ()) { + // + // Print the PciEx extend space in raw bytes ( 0xFF-0xFFF) + // + ShellPrintEx (-1, -1, L"\r\n%HStart dumping PCIex extended configuration space (0x100 - 0xFFF).%N\r\n\r\n"); + + DumpHex ( + 2, + EFI_PCIE_CAPABILITY_BASE_OFFSET, + ExtendedConfigSize, + ExtendedConfigSpace + ); + } + + // + // If "-i" appears in command line, interpret data in configuration space + // + if (ExplainData) { + PciExplainPci (&ConfigSpace, Address, IoDev); + if ((ExtendedConfigSpace != NULL) && !ShellGetExecutionBreakFlag ()) { + PciExplainPciExpress ( + (PCI_CAPABILITY_PCIEXP *) ((UINT8 *) &ConfigSpace + PcieCapabilityPtr), + ExtendedConfigSpace, + ExtendedConfigSize, + ExtendedCapability + ); + } + } + } +Done: + if (HandleBuf != NULL) { + FreePool (HandleBuf); + } + if (Package != NULL) { + ShellCommandLineFreeVarList (Package); + } + mConfigSpace = NULL; + return ShellStatus; +} + +/** + This function finds out the protocol which is in charge of the given + segment, and its bus range covers the current bus number. It lookes + each instances of RootBridgeIoProtocol handle, until the one meets the + criteria is found. + + @param[in] HandleBuf Buffer which holds all PCI_ROOT_BRIDIGE_IO_PROTOCOL handles. + @param[in] HandleCount Count of all PCI_ROOT_BRIDIGE_IO_PROTOCOL handles. + @param[in] Segment Segment number of device we are dealing with. + @param[in] Bus Bus number of device we are dealing with. + @param[out] IoDev Handle used to access configuration space of PCI device. + + @retval EFI_SUCCESS The command completed successfully. + @retval EFI_INVALID_PARAMETER Invalid parameter. + +**/ +EFI_STATUS +PciFindProtocolInterface ( + IN EFI_HANDLE *HandleBuf, + IN UINTN HandleCount, + IN UINT16 Segment, + IN UINT16 Bus, + OUT EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL **IoDev + ) +{ + UINTN Index; + EFI_STATUS Status; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors; + UINT16 MinBus; + UINT16 MaxBus; + BOOLEAN IsEnd; + + // + // Go through all handles, until the one meets the criteria is found + // + for (Index = 0; Index < HandleCount; Index++) { + Status = PciGetProtocolAndResource (HandleBuf[Index], IoDev, &Descriptors); + if (EFI_ERROR (Status)) { + return Status; + } + // + // When Descriptors == NULL, the Configuration() is not implemented, + // so we only check the Segment number + // + if (Descriptors == NULL && Segment == (*IoDev)->SegmentNumber) { + return EFI_SUCCESS; + } + + if ((*IoDev)->SegmentNumber != Segment) { + continue; + } + + while (TRUE) { + Status = PciGetNextBusRange (&Descriptors, &MinBus, &MaxBus, &IsEnd); + if (EFI_ERROR (Status)) { + return Status; + } + + if (IsEnd) { + break; + } + + if (MinBus <= Bus && MaxBus >= Bus) { + return EFI_SUCCESS; + } + } + } + + return EFI_NOT_FOUND; +} + +/** + This function gets the protocol interface from the given handle, and + obtains its address space descriptors. + + @param[in] Handle The PCI_ROOT_BRIDIGE_IO_PROTOCOL handle. + @param[out] IoDev Handle used to access configuration space of PCI device. + @param[out] Descriptors Points to the address space descriptors. + + @retval EFI_SUCCESS The command completed successfully +**/ +EFI_STATUS +PciGetProtocolAndResource ( + IN EFI_HANDLE Handle, + OUT EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL **IoDev, + OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors + ) +{ + EFI_STATUS Status; + + // + // Get inferface from protocol + // + Status = gBS->HandleProtocol ( + Handle, + &gEfiPciRootBridgeIoProtocolGuid, + (VOID**)IoDev + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // Call Configuration() to get address space descriptors + // + Status = (*IoDev)->Configuration (*IoDev, (VOID**)Descriptors); + if (Status == EFI_UNSUPPORTED) { + *Descriptors = NULL; + return EFI_SUCCESS; + + } else { + return Status; + } +} + +/** + This function get the next bus range of given address space descriptors. + It also moves the pointer backward a node, to get prepared to be called + again. + + @param[in, out] Descriptors Points to current position of a serial of address space + descriptors. + @param[out] MinBus The lower range of bus number. + @param[out] MaxBus The upper range of bus number. + @param[out] IsEnd Meet end of the serial of descriptors. + + @retval EFI_SUCCESS The command completed successfully. +**/ +EFI_STATUS +PciGetNextBusRange ( + IN OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors, + OUT UINT16 *MinBus, + OUT UINT16 *MaxBus, + OUT BOOLEAN *IsEnd + ) +{ + *IsEnd = FALSE; + + // + // When *Descriptors is NULL, Configuration() is not implemented, so assume + // range is 0~PCI_MAX_BUS + // + if ((*Descriptors) == NULL) { + *MinBus = 0; + *MaxBus = PCI_MAX_BUS; + return EFI_SUCCESS; + } + // + // *Descriptors points to one or more address space descriptors, which + // ends with a end tagged descriptor. Examine each of the descriptors, + // if a bus typed one is found and its bus range covers bus, this handle + // is the handle we are looking for. + // + + while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) { + if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) { + *MinBus = (UINT16) (*Descriptors)->AddrRangeMin; + *MaxBus = (UINT16) (*Descriptors)->AddrRangeMax; + (*Descriptors)++; + return (EFI_SUCCESS); + } + + (*Descriptors)++; + } + + if ((*Descriptors)->Desc == ACPI_END_TAG_DESCRIPTOR) { + *IsEnd = TRUE; + } + + return EFI_SUCCESS; +} + +/** + Explain the data in PCI configuration space. The part which is common for + PCI device and bridge is interpreted in this function. It calls other + functions to interpret data unique for device or bridge. + + @param[in] ConfigSpace Data in PCI configuration space. + @param[in] Address Address used to access configuration space of this PCI device. + @param[in] IoDev Handle used to access configuration space of PCI device. +**/ +VOID +PciExplainPci ( + IN PCI_CONFIG_SPACE *ConfigSpace, + IN UINT64 Address, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev + ) +{ + PCI_DEVICE_INDEPENDENT_REGION *Common; + PCI_HEADER_TYPE HeaderType; + + Common = &(ConfigSpace->Common); + + ShellPrintEx (-1, -1, L"\r\n"); + + // + // Print Vendor Id and Device Id + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_PCI_LINE_VID_DID), gShellDebug1HiiHandle, + INDEX_OF (&(Common->VendorId)), + Common->VendorId, + INDEX_OF (&(Common->DeviceId)), + Common->DeviceId + ); + + // + // Print register Command + // + PciExplainCommand (&(Common->Command)); + + // + // Print register Status + // + PciExplainStatus (&(Common->Status), TRUE, PciUndefined); + + // + // Print register Revision ID + // + ShellPrintEx(-1, -1, L"\r\n"); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_PCI_LINE_RID), gShellDebug1HiiHandle, + INDEX_OF (&(Common->RevisionID)), + Common->RevisionID + ); + + // + // Print register BIST + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_PCI_LINE_BIST), gShellDebug1HiiHandle, INDEX_OF (&(Common->BIST))); + if ((Common->BIST & BIT7) != 0) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_PCI_LINE_CAP), gShellDebug1HiiHandle, 0x0f & Common->BIST); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_PCI_LINE_CAP_NO), gShellDebug1HiiHandle); + } + // + // Print register Cache Line Size + // + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_CACHE_LINE_SIZE), + gShellDebug1HiiHandle, + INDEX_OF (&(Common->CacheLineSize)), + Common->CacheLineSize + ); + + // + // Print register Latency Timer + // + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_LATENCY_TIMER), + gShellDebug1HiiHandle, + INDEX_OF (&(Common->LatencyTimer)), + Common->LatencyTimer + ); + + // + // Print register Header Type + // + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_HEADER_TYPE), + gShellDebug1HiiHandle, + INDEX_OF (&(Common->HeaderType)), + Common->HeaderType + ); + + if ((Common->HeaderType & BIT7) != 0) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_MULTI_FUNCTION), gShellDebug1HiiHandle); + + } else { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_SINGLE_FUNCTION), gShellDebug1HiiHandle); + } + + HeaderType = (PCI_HEADER_TYPE)(UINT8) (Common->HeaderType & 0x7f); + switch (HeaderType) { + case PciDevice: + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_PCI_DEVICE), gShellDebug1HiiHandle); + break; + + case PciP2pBridge: + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_P2P_BRIDGE), gShellDebug1HiiHandle); + break; + + case PciCardBusBridge: + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_CARDBUS_BRIDGE), gShellDebug1HiiHandle); + break; + + default: + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_RESERVED), gShellDebug1HiiHandle); + HeaderType = PciUndefined; + } + + // + // Print register Class Code + // + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_CLASS), gShellDebug1HiiHandle); + PciPrintClassCode ((UINT8 *) Common->ClassCode, TRUE); + ShellPrintEx (-1, -1, L"\r\n"); +} + +/** + Explain the device specific part of data in PCI configuration space. + + @param[in] Device Data in PCI configuration space. + @param[in] Address Address used to access configuration space of this PCI device. + @param[in] IoDev Handle used to access configuration space of PCI device. + + @retval EFI_SUCCESS The command completed successfully. +**/ +EFI_STATUS +PciExplainDeviceData ( + IN PCI_DEVICE_HEADER_TYPE_REGION *Device, + IN UINT64 Address, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev + ) +{ + UINTN Index; + BOOLEAN BarExist; + EFI_STATUS Status; + UINTN BarCount; + + // + // Print Base Address Registers(Bar). When Bar = 0, this Bar does not + // exist. If these no Bar for this function, print "none", otherwise + // list detail information about this Bar. + // + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_BASE_ADDR), gShellDebug1HiiHandle, INDEX_OF (Device->Bar)); + + BarExist = FALSE; + BarCount = sizeof (Device->Bar) / sizeof (Device->Bar[0]); + for (Index = 0; Index < BarCount; Index++) { + if (Device->Bar[Index] == 0) { + continue; + } + + if (!BarExist) { + BarExist = TRUE; + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_START_TYPE), gShellDebug1HiiHandle); + ShellPrintEx (-1, -1, L" --------------------------------------------------------------------------"); + } + + Status = PciExplainBar ( + &(Device->Bar[Index]), + &(mConfigSpace->Common.Command), + Address, + IoDev, + &Index + ); + + if (EFI_ERROR (Status)) { + break; + } + } + + if (!BarExist) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_NONE), gShellDebug1HiiHandle); + + } else { + ShellPrintEx (-1, -1, L"\r\n --------------------------------------------------------------------------"); + } + + // + // Print register Expansion ROM Base Address + // + if ((Device->ExpansionRomBar & BIT0) == 0) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_EXPANSION_ROM_DISABLED), gShellDebug1HiiHandle, INDEX_OF (&(Device->ExpansionRomBar))); + + } else { + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_EXPANSION_ROM_BASE), + gShellDebug1HiiHandle, + INDEX_OF (&(Device->ExpansionRomBar)), + Device->ExpansionRomBar + ); + } + // + // Print register Cardbus CIS ptr + // + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_CARDBUS_CIS), + gShellDebug1HiiHandle, + INDEX_OF (&(Device->CISPtr)), + Device->CISPtr + ); + + // + // Print register Sub-vendor ID and subsystem ID + // + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_SUB_VENDOR_ID), + gShellDebug1HiiHandle, + INDEX_OF (&(Device->SubsystemVendorID)), + Device->SubsystemVendorID + ); + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_SUBSYSTEM_ID), + gShellDebug1HiiHandle, + INDEX_OF (&(Device->SubsystemID)), + Device->SubsystemID + ); + + // + // Print register Capabilities Ptr + // + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_CAPABILITIES_PTR), + gShellDebug1HiiHandle, + INDEX_OF (&(Device->CapabilityPtr)), + Device->CapabilityPtr + ); + + // + // Print register Interrupt Line and interrupt pin + // + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_INTERRUPT_LINE), + gShellDebug1HiiHandle, + INDEX_OF (&(Device->InterruptLine)), + Device->InterruptLine + ); + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_INTERRUPT_PIN), + gShellDebug1HiiHandle, + INDEX_OF (&(Device->InterruptPin)), + Device->InterruptPin + ); + + // + // Print register Min_Gnt and Max_Lat + // + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_MIN_GNT), + gShellDebug1HiiHandle, + INDEX_OF (&(Device->MinGnt)), + Device->MinGnt + ); + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_MAX_LAT), + gShellDebug1HiiHandle, + INDEX_OF (&(Device->MaxLat)), + Device->MaxLat + ); + + return EFI_SUCCESS; +} + +/** + Explain the bridge specific part of data in PCI configuration space. + + @param[in] Bridge Bridge specific data region in PCI configuration space. + @param[in] Address Address used to access configuration space of this PCI device. + @param[in] IoDev Handle used to access configuration space of PCI device. + + @retval EFI_SUCCESS The command completed successfully. +**/ +EFI_STATUS +PciExplainBridgeData ( + IN PCI_BRIDGE_CONTROL_REGISTER *Bridge, + IN UINT64 Address, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev + ) +{ + UINTN Index; + BOOLEAN BarExist; + UINTN BarCount; + UINT32 IoAddress32; + EFI_STATUS Status; + + // + // Print Base Address Registers. When Bar = 0, this Bar does not + // exist. If these no Bar for this function, print "none", otherwise + // list detail information about this Bar. + // + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_BASE_ADDRESS), gShellDebug1HiiHandle, INDEX_OF (&(Bridge->Bar))); + + BarExist = FALSE; + BarCount = sizeof (Bridge->Bar) / sizeof (Bridge->Bar[0]); + + for (Index = 0; Index < BarCount; Index++) { + if (Bridge->Bar[Index] == 0) { + continue; + } + + if (!BarExist) { + BarExist = TRUE; + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_START_TYPE_2), gShellDebug1HiiHandle); + ShellPrintEx (-1, -1, L" --------------------------------------------------------------------------"); + } + + Status = PciExplainBar ( + &(Bridge->Bar[Index]), + &(mConfigSpace->Common.Command), + Address, + IoDev, + &Index + ); + + if (EFI_ERROR (Status)) { + break; + } + } + + if (!BarExist) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_NONE), gShellDebug1HiiHandle); + } else { + ShellPrintEx (-1, -1, L"\r\n --------------------------------------------------------------------------"); + } + + // + // Expansion register ROM Base Address + // + if ((Bridge->ExpansionRomBAR & BIT0) == 0) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_NO_EXPANSION_ROM), gShellDebug1HiiHandle, INDEX_OF (&(Bridge->ExpansionRomBAR))); + + } else { + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_EXPANSION_ROM_BASE_2), + gShellDebug1HiiHandle, + INDEX_OF (&(Bridge->ExpansionRomBAR)), + Bridge->ExpansionRomBAR + ); + } + // + // Print Bus Numbers(Primary, Secondary, and Subordinate + // + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_BUS_NUMBERS), + gShellDebug1HiiHandle, + INDEX_OF (&(Bridge->PrimaryBus)), + INDEX_OF (&(Bridge->SecondaryBus)), + INDEX_OF (&(Bridge->SubordinateBus)) + ); + + ShellPrintEx (-1, -1, L" ------------------------------------------------------\r\n"); + + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_BRIDGE), gShellDebug1HiiHandle, Bridge->PrimaryBus); + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_BRIDGE), gShellDebug1HiiHandle, Bridge->SecondaryBus); + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_BRIDGE), gShellDebug1HiiHandle, Bridge->SubordinateBus); + + // + // Print register Secondary Latency Timer + // + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_SECONDARY_TIMER), + gShellDebug1HiiHandle, + INDEX_OF (&(Bridge->SecondaryLatencyTimer)), + Bridge->SecondaryLatencyTimer + ); + + // + // Print register Secondary Status + // + PciExplainStatus (&(Bridge->SecondaryStatus), FALSE, PciP2pBridge); + + // + // Print I/O and memory ranges this bridge forwards. There are 3 resource + // types: I/O, memory, and pre-fetchable memory. For each resource type, + // base and limit address are listed. + // + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_RESOURCE_TYPE), gShellDebug1HiiHandle); + ShellPrintEx (-1, -1, L"----------------------------------------------------------------------\r\n"); + + // + // IO Base & Limit + // + IoAddress32 = (Bridge->IoBaseUpper16 << 16 | Bridge->IoBase << 8); + IoAddress32 &= 0xfffff000; + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_TWO_VARS), + gShellDebug1HiiHandle, + INDEX_OF (&(Bridge->IoBase)), + IoAddress32 + ); + + IoAddress32 = (Bridge->IoLimitUpper16 << 16 | Bridge->IoLimit << 8); + IoAddress32 |= 0x00000fff; + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_ONE_VAR), gShellDebug1HiiHandle, IoAddress32); + + // + // Memory Base & Limit + // + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_MEMORY), + gShellDebug1HiiHandle, + INDEX_OF (&(Bridge->MemoryBase)), + (Bridge->MemoryBase << 16) & 0xfff00000 + ); + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_ONE_VAR), + gShellDebug1HiiHandle, + (Bridge->MemoryLimit << 16) | 0x000fffff + ); + + // + // Pre-fetch-able Memory Base & Limit + // + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_PREFETCHABLE), + gShellDebug1HiiHandle, + INDEX_OF (&(Bridge->PrefetchableMemoryBase)), + Bridge->PrefetchableBaseUpper32, + (Bridge->PrefetchableMemoryBase << 16) & 0xfff00000 + ); + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_TWO_VARS_2), + gShellDebug1HiiHandle, + Bridge->PrefetchableLimitUpper32, + (Bridge->PrefetchableMemoryLimit << 16) | 0x000fffff + ); + + // + // Print register Capabilities Pointer + // + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_CAPABILITIES_PTR_2), + gShellDebug1HiiHandle, + INDEX_OF (&(Bridge->CapabilityPtr)), + Bridge->CapabilityPtr + ); + + // + // Print register Bridge Control + // + PciExplainBridgeControl (&(Bridge->BridgeControl), PciP2pBridge); + + // + // Print register Interrupt Line & PIN + // + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_INTERRUPT_LINE_2), + gShellDebug1HiiHandle, + INDEX_OF (&(Bridge->InterruptLine)), + Bridge->InterruptLine + ); + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_INTERRUPT_PIN), + gShellDebug1HiiHandle, + INDEX_OF (&(Bridge->InterruptPin)), + Bridge->InterruptPin + ); + + return EFI_SUCCESS; +} + +/** + Explain the Base Address Register(Bar) in PCI configuration space. + + @param[in] Bar Points to the Base Address Register intended to interpret. + @param[in] Command Points to the register Command. + @param[in] Address Address used to access configuration space of this PCI device. + @param[in] IoDev Handle used to access configuration space of PCI device. + @param[in, out] Index The Index. + + @retval EFI_SUCCESS The command completed successfully. +**/ +EFI_STATUS +PciExplainBar ( + IN UINT32 *Bar, + IN UINT16 *Command, + IN UINT64 Address, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, + IN OUT UINTN *Index + ) +{ + UINT16 OldCommand; + UINT16 NewCommand; + UINT64 Bar64; + UINT32 OldBar32; + UINT32 NewBar32; + UINT64 OldBar64; + UINT64 NewBar64; + BOOLEAN IsMem; + BOOLEAN IsBar32; + UINT64 RegAddress; + + IsBar32 = TRUE; + Bar64 = 0; + NewBar32 = 0; + NewBar64 = 0; + + // + // According the bar type, list detail about this bar, for example: 32 or + // 64 bits; pre-fetchable or not. + // + if ((*Bar & BIT0) == 0) { + // + // This bar is of memory type + // + IsMem = TRUE; + + if ((*Bar & BIT1) == 0 && (*Bar & BIT2) == 0) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_BAR), gShellDebug1HiiHandle, *Bar & 0xfffffff0); + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_MEM), gShellDebug1HiiHandle); + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_32_BITS), gShellDebug1HiiHandle); + + } else if ((*Bar & BIT1) == 0 && (*Bar & BIT2) != 0) { + Bar64 = 0x0; + CopyMem (&Bar64, Bar, sizeof (UINT64)); + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_ONE_VAR_2), gShellDebug1HiiHandle, (UINT32) RShiftU64 ((Bar64 & 0xfffffffffffffff0ULL), 32)); + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_ONE_VAR_3), gShellDebug1HiiHandle, (UINT32) (Bar64 & 0xfffffffffffffff0ULL)); + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_MEM), gShellDebug1HiiHandle); + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_64_BITS), gShellDebug1HiiHandle); + IsBar32 = FALSE; + *Index += 1; + + } else { + // + // Reserved + // + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_BAR), gShellDebug1HiiHandle, *Bar & 0xfffffff0); + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_MEM_2), gShellDebug1HiiHandle); + } + + if ((*Bar & BIT3) == 0) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_NO), gShellDebug1HiiHandle); + + } else { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_YES), gShellDebug1HiiHandle); + } + + } else { + // + // This bar is of io type + // + IsMem = FALSE; + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_ONE_VAR_4), gShellDebug1HiiHandle, *Bar & 0xfffffffc); + ShellPrintEx (-1, -1, L"I/O "); + } + + // + // Get BAR length(or the amount of resource this bar demands for). To get + // Bar length, first we should temporarily disable I/O and memory access + // of this function(by set bits in the register Command), then write all + // "1"s to this bar. The bar value read back is the amount of resource + // this bar demands for. + // + // + // Disable io & mem access + // + OldCommand = *Command; + NewCommand = (UINT16) (OldCommand & 0xfffc); + RegAddress = Address | INDEX_OF (Command); + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, RegAddress, 1, &NewCommand); + + RegAddress = Address | INDEX_OF (Bar); + + // + // Read after write the BAR to get the size + // + if (IsBar32) { + OldBar32 = *Bar; + NewBar32 = 0xffffffff; + + IoDev->Pci.Write (IoDev, EfiPciWidthUint32, RegAddress, 1, &NewBar32); + IoDev->Pci.Read (IoDev, EfiPciWidthUint32, RegAddress, 1, &NewBar32); + IoDev->Pci.Write (IoDev, EfiPciWidthUint32, RegAddress, 1, &OldBar32); + + if (IsMem) { + NewBar32 = NewBar32 & 0xfffffff0; + NewBar32 = (~NewBar32) + 1; + + } else { + NewBar32 = NewBar32 & 0xfffffffc; + NewBar32 = (~NewBar32) + 1; + NewBar32 = NewBar32 & 0x0000ffff; + } + } else { + + OldBar64 = 0x0; + CopyMem (&OldBar64, Bar, sizeof (UINT64)); + NewBar64 = 0xffffffffffffffffULL; + + IoDev->Pci.Write (IoDev, EfiPciWidthUint32, RegAddress, 2, &NewBar64); + IoDev->Pci.Read (IoDev, EfiPciWidthUint32, RegAddress, 2, &NewBar64); + IoDev->Pci.Write (IoDev, EfiPciWidthUint32, RegAddress, 2, &OldBar64); + + if (IsMem) { + NewBar64 = NewBar64 & 0xfffffffffffffff0ULL; + NewBar64 = (~NewBar64) + 1; + + } else { + NewBar64 = NewBar64 & 0xfffffffffffffffcULL; + NewBar64 = (~NewBar64) + 1; + NewBar64 = NewBar64 & 0x000000000000ffff; + } + } + // + // Enable io & mem access + // + RegAddress = Address | INDEX_OF (Command); + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, RegAddress, 1, &OldCommand); + + if (IsMem) { + if (IsBar32) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_NEWBAR_32), gShellDebug1HiiHandle, NewBar32); + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_NEWBAR_32_2), gShellDebug1HiiHandle, NewBar32 + (*Bar & 0xfffffff0) - 1); + + } else { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_RSHIFT), gShellDebug1HiiHandle, (UINT32) RShiftU64 (NewBar64, 32)); + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_RSHIFT), gShellDebug1HiiHandle, (UINT32) NewBar64); + ShellPrintEx (-1, -1, L" "); + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_RSHIFT), + gShellDebug1HiiHandle, + (UINT32) RShiftU64 ((NewBar64 + (Bar64 & 0xfffffffffffffff0ULL) - 1), 32) + ); + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_RSHIFT), gShellDebug1HiiHandle, (UINT32) (NewBar64 + (Bar64 & 0xfffffffffffffff0ULL) - 1)); + + } + } else { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_NEWBAR_32_3), gShellDebug1HiiHandle, NewBar32); + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_NEWBAR_32_4), gShellDebug1HiiHandle, NewBar32 + (*Bar & 0xfffffffc) - 1); + } + + return EFI_SUCCESS; +} + +/** + Explain the cardbus specific part of data in PCI configuration space. + + @param[in] CardBus CardBus specific region of PCI configuration space. + @param[in] Address Address used to access configuration space of this PCI device. + @param[in] IoDev Handle used to access configuration space of PCI device. + + @retval EFI_SUCCESS The command completed successfully. +**/ +EFI_STATUS +PciExplainCardBusData ( + IN PCI_CARDBUS_CONTROL_REGISTER *CardBus, + IN UINT64 Address, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev + ) +{ + BOOLEAN Io32Bit; + PCI_CARDBUS_DATA *CardBusData; + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_CARDBUS_SOCKET), + gShellDebug1HiiHandle, + INDEX_OF (&(CardBus->CardBusSocketReg)), + CardBus->CardBusSocketReg + ); + + // + // Print Secondary Status + // + PciExplainStatus (&(CardBus->SecondaryStatus), FALSE, PciCardBusBridge); + + // + // Print Bus Numbers(Primary bus number, CardBus bus number, and + // Subordinate bus number + // + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_BUS_NUMBERS_2), + gShellDebug1HiiHandle, + INDEX_OF (&(CardBus->PciBusNumber)), + INDEX_OF (&(CardBus->CardBusBusNumber)), + INDEX_OF (&(CardBus->SubordinateBusNumber)) + ); + + ShellPrintEx (-1, -1, L" ------------------------------------------------------\r\n"); + + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_CARDBUS), gShellDebug1HiiHandle, CardBus->PciBusNumber); + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_CARDBUS_2), gShellDebug1HiiHandle, CardBus->CardBusBusNumber); + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_CARDBUS_3), gShellDebug1HiiHandle, CardBus->SubordinateBusNumber); + + // + // Print CardBus Latency Timer + // + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_CARDBUS_LATENCY), + gShellDebug1HiiHandle, + INDEX_OF (&(CardBus->CardBusLatencyTimer)), + CardBus->CardBusLatencyTimer + ); + + // + // Print Memory/Io ranges this cardbus bridge forwards + // + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_RESOURCE_TYPE_2), gShellDebug1HiiHandle); + ShellPrintEx (-1, -1, L"----------------------------------------------------------------------\r\n"); + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_MEM_3), + gShellDebug1HiiHandle, + INDEX_OF (&(CardBus->MemoryBase0)), + CardBus->BridgeControl & BIT8 ? L" Prefetchable" : L"Non-Prefetchable", + CardBus->MemoryBase0 & 0xfffff000, + CardBus->MemoryLimit0 | 0x00000fff + ); + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_MEM_3), + gShellDebug1HiiHandle, + INDEX_OF (&(CardBus->MemoryBase1)), + CardBus->BridgeControl & BIT9 ? L" Prefetchable" : L"Non-Prefetchable", + CardBus->MemoryBase1 & 0xfffff000, + CardBus->MemoryLimit1 | 0x00000fff + ); + + Io32Bit = (BOOLEAN) (CardBus->IoBase0 & BIT0); + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_IO_2), + gShellDebug1HiiHandle, + INDEX_OF (&(CardBus->IoBase0)), + Io32Bit ? L" 32 bit" : L" 16 bit", + CardBus->IoBase0 & (Io32Bit ? 0xfffffffc : 0x0000fffc), + (CardBus->IoLimit0 & (Io32Bit ? 0xffffffff : 0x0000ffff)) | 0x00000003 + ); + + Io32Bit = (BOOLEAN) (CardBus->IoBase1 & BIT0); + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_IO_2), + gShellDebug1HiiHandle, + INDEX_OF (&(CardBus->IoBase1)), + Io32Bit ? L" 32 bit" : L" 16 bit", + CardBus->IoBase1 & (Io32Bit ? 0xfffffffc : 0x0000fffc), + (CardBus->IoLimit1 & (Io32Bit ? 0xffffffff : 0x0000ffff)) | 0x00000003 + ); + + // + // Print register Interrupt Line & PIN + // + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_INTERRUPT_LINE_3), + gShellDebug1HiiHandle, + INDEX_OF (&(CardBus->InterruptLine)), + CardBus->InterruptLine, + INDEX_OF (&(CardBus->InterruptPin)), + CardBus->InterruptPin + ); + + // + // Print register Bridge Control + // + PciExplainBridgeControl (&(CardBus->BridgeControl), PciCardBusBridge); + + // + // Print some registers in data region of PCI configuration space for cardbus + // bridge. Fields include: Sub VendorId, Subsystem ID, and Legacy Mode Base + // Address. + // + CardBusData = (PCI_CARDBUS_DATA *) ((UINT8 *) CardBus + sizeof (PCI_CARDBUS_CONTROL_REGISTER)); + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_SUB_VENDOR_ID_2), + gShellDebug1HiiHandle, + INDEX_OF (&(CardBusData->SubVendorId)), + CardBusData->SubVendorId, + INDEX_OF (&(CardBusData->SubSystemId)), + CardBusData->SubSystemId + ); + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_OPTIONAL), + gShellDebug1HiiHandle, + INDEX_OF (&(CardBusData->LegacyBase)), + CardBusData->LegacyBase + ); + + return EFI_SUCCESS; +} + +/** + Explain each meaningful bit of register Status. The definition of Status is + slightly different depending on the PCI header type. + + @param[in] Status Points to the content of register Status. + @param[in] MainStatus Indicates if this register is main status(not secondary + status). + @param[in] HeaderType Header type of this PCI device. + + @retval EFI_SUCCESS The command completed successfully. +**/ +EFI_STATUS +PciExplainStatus ( + IN UINT16 *Status, + IN BOOLEAN MainStatus, + IN PCI_HEADER_TYPE HeaderType + ) +{ + if (MainStatus) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_STATUS), gShellDebug1HiiHandle, INDEX_OF (Status), *Status); + + } else { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_SECONDARY_STATUS), gShellDebug1HiiHandle, INDEX_OF (Status), *Status); + } + + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_NEW_CAPABILITIES), gShellDebug1HiiHandle, (*Status & BIT4) != 0); + + // + // Bit 5 is meaningless for CardBus Bridge + // + if (HeaderType == PciCardBusBridge) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_66_CAPABLE), gShellDebug1HiiHandle, (*Status & BIT5) != 0); + + } else { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_66_CAPABLE_2), gShellDebug1HiiHandle, (*Status & BIT5) != 0); + } + + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_FAST_BACK), gShellDebug1HiiHandle, (*Status & BIT7) != 0); + + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_MASTER_DATA), gShellDebug1HiiHandle, (*Status & BIT8) != 0); + // + // Bit 9 and bit 10 together decides the DEVSEL timing + // + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_DEVSEL_TIMING), gShellDebug1HiiHandle); + if ((*Status & BIT9) == 0 && (*Status & BIT10) == 0) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_FAST), gShellDebug1HiiHandle); + + } else if ((*Status & BIT9) != 0 && (*Status & BIT10) == 0) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_MEDIUM), gShellDebug1HiiHandle); + + } else if ((*Status & BIT9) == 0 && (*Status & BIT10) != 0) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_SLOW), gShellDebug1HiiHandle); + + } else { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_RESERVED_2), gShellDebug1HiiHandle); + } + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_SIGNALED_TARGET), + gShellDebug1HiiHandle, + (*Status & BIT11) != 0 + ); + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_RECEIVED_TARGET), + gShellDebug1HiiHandle, + (*Status & BIT12) != 0 + ); + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_RECEIVED_MASTER), + gShellDebug1HiiHandle, + (*Status & BIT13) != 0 + ); + + if (MainStatus) { + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_SIGNALED_ERROR), + gShellDebug1HiiHandle, + (*Status & BIT14) != 0 + ); + + } else { + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_RECEIVED_ERROR), + gShellDebug1HiiHandle, + (*Status & BIT14) != 0 + ); + } + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_DETECTED_ERROR), + gShellDebug1HiiHandle, + (*Status & BIT15) != 0 + ); + + return EFI_SUCCESS; +} + +/** + Explain each meaningful bit of register Command. + + @param[in] Command Points to the content of register Command. + + @retval EFI_SUCCESS The command completed successfully. +**/ +EFI_STATUS +PciExplainCommand ( + IN UINT16 *Command + ) +{ + // + // Print the binary value of register Command + // + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_PCI2_COMMAND), gShellDebug1HiiHandle, INDEX_OF (Command), *Command); + + // + // Explain register Command bit by bit + // + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_SPACE_ACCESS_DENIED), + gShellDebug1HiiHandle, + (*Command & BIT0) != 0 + ); + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_MEMORY_SPACE), + gShellDebug1HiiHandle, + (*Command & BIT1) != 0 + ); + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_BEHAVE_BUS_MASTER), + gShellDebug1HiiHandle, + (*Command & BIT2) != 0 + ); + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_MONITOR_SPECIAL_CYCLE), + gShellDebug1HiiHandle, + (*Command & BIT3) != 0 + ); + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_MEM_WRITE_INVALIDATE), + gShellDebug1HiiHandle, + (*Command & BIT4) != 0 + ); + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_PALETTE_SNOOPING), + gShellDebug1HiiHandle, + (*Command & BIT5) != 0 + ); + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_ASSERT_PERR), + gShellDebug1HiiHandle, + (*Command & BIT6) != 0 + ); + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_DO_ADDR_STEPPING), + gShellDebug1HiiHandle, + (*Command & BIT7) != 0 + ); + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_SERR_DRIVER), + gShellDebug1HiiHandle, + (*Command & BIT8) != 0 + ); + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_FAST_BACK_2), + gShellDebug1HiiHandle, + (*Command & BIT9) != 0 + ); + + return EFI_SUCCESS; +} + +/** + Explain each meaningful bit of register Bridge Control. + + @param[in] BridgeControl Points to the content of register Bridge Control. + @param[in] HeaderType The headertype. + + @retval EFI_SUCCESS The command completed successfully. +**/ +EFI_STATUS +PciExplainBridgeControl ( + IN UINT16 *BridgeControl, + IN PCI_HEADER_TYPE HeaderType + ) +{ + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_BRIDGE_CONTROL), + gShellDebug1HiiHandle, + INDEX_OF (BridgeControl), + *BridgeControl + ); + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_PARITY_ERROR), + gShellDebug1HiiHandle, + (*BridgeControl & BIT0) != 0 + ); + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_SERR_ENABLE), + gShellDebug1HiiHandle, + (*BridgeControl & BIT1) != 0 + ); + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_ISA_ENABLE), + gShellDebug1HiiHandle, + (*BridgeControl & BIT2) != 0 + ); + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_VGA_ENABLE), + gShellDebug1HiiHandle, + (*BridgeControl & BIT3) != 0 + ); + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_MASTER_ABORT), + gShellDebug1HiiHandle, + (*BridgeControl & BIT5) != 0 + ); + + // + // Register Bridge Control has some slight differences between P2P bridge + // and Cardbus bridge from bit 6 to bit 11. + // + if (HeaderType == PciP2pBridge) { + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_SECONDARY_BUS_RESET), + gShellDebug1HiiHandle, + (*BridgeControl & BIT6) != 0 + ); + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_FAST_ENABLE), + gShellDebug1HiiHandle, + (*BridgeControl & BIT7) != 0 + ); + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_PRIMARY_DISCARD_TIMER), + gShellDebug1HiiHandle, + (*BridgeControl & BIT8)!=0 ? L"2^10" : L"2^15" + ); + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_SECONDARY_DISCARD_TIMER), + gShellDebug1HiiHandle, + (*BridgeControl & BIT9)!=0 ? L"2^10" : L"2^15" + ); + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_DISCARD_TIMER_STATUS), + gShellDebug1HiiHandle, + (*BridgeControl & BIT10) != 0 + ); + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_DISCARD_TIMER_SERR), + gShellDebug1HiiHandle, + (*BridgeControl & BIT11) != 0 + ); + + } else { + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_CARDBUS_RESET), + gShellDebug1HiiHandle, + (*BridgeControl & BIT6) != 0 + ); + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_IREQ_ENABLE), + gShellDebug1HiiHandle, + (*BridgeControl & BIT7) != 0 + ); + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_PCI2_WRITE_POSTING_ENABLE), + gShellDebug1HiiHandle, + (*BridgeControl & BIT10) != 0 + ); + } + + return EFI_SUCCESS; +} + +/** + Locate capability register block per capability ID. + + @param[in] ConfigSpace Data in PCI configuration space. + @param[in] CapabilityId The capability ID. + + @return The offset of the register block per capability ID, + or 0 if the register block cannot be found. +**/ +UINT8 +LocatePciCapability ( + IN PCI_CONFIG_SPACE *ConfigSpace, + IN UINT8 CapabilityId + ) +{ + UINT8 CapabilityPtr; + EFI_PCI_CAPABILITY_HDR *CapabilityEntry; + + // + // To check the cpability of this device supports + // + if ((ConfigSpace->Common.Status & EFI_PCI_STATUS_CAPABILITY) == 0) { + return 0; + } + + switch ((PCI_HEADER_TYPE)(ConfigSpace->Common.HeaderType & 0x7f)) { + case PciDevice: + CapabilityPtr = ConfigSpace->NonCommon.Device.CapabilityPtr; + break; + case PciP2pBridge: + CapabilityPtr = ConfigSpace->NonCommon.Bridge.CapabilityPtr; + break; + case PciCardBusBridge: + CapabilityPtr = ConfigSpace->NonCommon.CardBus.Cap_Ptr; + break; + default: + return 0; + } + + while ((CapabilityPtr >= 0x40) && ((CapabilityPtr & 0x03) == 0x00)) { + CapabilityEntry = (EFI_PCI_CAPABILITY_HDR *) ((UINT8 *) ConfigSpace + CapabilityPtr); + if (CapabilityEntry->CapabilityID == CapabilityId) { + return CapabilityPtr; + } + + // + // Certain PCI device may incorrectly have capability pointing to itself, + // break to avoid dead loop. + // + if (CapabilityPtr == CapabilityEntry->NextItemPtr) { + break; + } + + CapabilityPtr = CapabilityEntry->NextItemPtr; + } + + return 0; +} + +/** + Print out information of the capability information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieCapReg ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ) +{ + CHAR16 *DevicePortType; + + ShellPrintEx (-1, -1, + L" Capability Version(3:0): %E0x%04x%N\r\n", + PciExpressCap->Capability.Bits.Version + ); + if (PciExpressCap->Capability.Bits.DevicePortType < ARRAY_SIZE (DevicePortTypeTable)) { + DevicePortType = DevicePortTypeTable[PciExpressCap->Capability.Bits.DevicePortType]; + } else { + DevicePortType = L"Unknown Type"; + } + ShellPrintEx (-1, -1, + L" Device/PortType(7:4): %E%s%N\r\n", + DevicePortType + ); + // + // 'Slot Implemented' is only valid for: + // a) Root Port of PCI Express Root Complex, or + // b) Downstream Port of PCI Express Switch + // + if (PciExpressCap->Capability.Bits.DevicePortType== PCIE_DEVICE_PORT_TYPE_ROOT_PORT || + PciExpressCap->Capability.Bits.DevicePortType == PCIE_DEVICE_PORT_TYPE_DOWNSTREAM_PORT) { + ShellPrintEx (-1, -1, + L" Slot Implemented(8): %E%d%N\r\n", + PciExpressCap->Capability.Bits.SlotImplemented + ); + } + ShellPrintEx (-1, -1, + L" Interrupt Message Number(13:9): %E0x%05x%N\r\n", + PciExpressCap->Capability.Bits.InterruptMessageNumber + ); + return EFI_SUCCESS; +} + +/** + Print out information of the device capability information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieDeviceCap ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ) +{ + UINT8 DevicePortType; + UINT8 L0sLatency; + UINT8 L1Latency; + + DevicePortType = (UINT8)PciExpressCap->Capability.Bits.DevicePortType; + ShellPrintEx (-1, -1, L" Max_Payload_Size Supported(2:0): "); + if (PciExpressCap->DeviceCapability.Bits.MaxPayloadSize < 6) { + ShellPrintEx (-1, -1, L"%E%d bytes%N\r\n", 1 << (PciExpressCap->DeviceCapability.Bits.MaxPayloadSize + 7)); + } else { + ShellPrintEx (-1, -1, L"%EUnknown%N\r\n"); + } + ShellPrintEx (-1, -1, + L" Phantom Functions Supported(4:3): %E%d%N\r\n", + PciExpressCap->DeviceCapability.Bits.PhantomFunctions + ); + ShellPrintEx (-1, -1, + L" Extended Tag Field Supported(5): %E%d-bit Tag field supported%N\r\n", + PciExpressCap->DeviceCapability.Bits.ExtendedTagField ? 8 : 5 + ); + // + // Endpoint L0s and L1 Acceptable Latency is only valid for Endpoint + // + if (IS_PCIE_ENDPOINT (DevicePortType)) { + L0sLatency = (UINT8)PciExpressCap->DeviceCapability.Bits.EndpointL0sAcceptableLatency; + L1Latency = (UINT8)PciExpressCap->DeviceCapability.Bits.EndpointL1AcceptableLatency; + ShellPrintEx (-1, -1, L" Endpoint L0s Acceptable Latency(8:6): "); + if (L0sLatency < 4) { + ShellPrintEx (-1, -1, L"%EMaximum of %d ns%N\r\n", 1 << (L0sLatency + 6)); + } else { + if (L0sLatency < 7) { + ShellPrintEx (-1, -1, L"%EMaximum of %d us%N\r\n", 1 << (L0sLatency - 3)); + } else { + ShellPrintEx (-1, -1, L"%ENo limit%N\r\n"); + } + } + ShellPrintEx (-1, -1, L" Endpoint L1 Acceptable Latency(11:9): "); + if (L1Latency < 7) { + ShellPrintEx (-1, -1, L"%EMaximum of %d us%N\r\n", 1 << (L1Latency + 1)); + } else { + ShellPrintEx (-1, -1, L"%ENo limit%N\r\n"); + } + } + ShellPrintEx (-1, -1, + L" Role-based Error Reporting(15): %E%d%N\r\n", + PciExpressCap->DeviceCapability.Bits.RoleBasedErrorReporting + ); + // + // Only valid for Upstream Port: + // a) Captured Slot Power Limit Value + // b) Captured Slot Power Scale + // + if (DevicePortType == PCIE_DEVICE_PORT_TYPE_UPSTREAM_PORT) { + ShellPrintEx (-1, -1, + L" Captured Slot Power Limit Value(25:18): %E0x%02x%N\r\n", + PciExpressCap->DeviceCapability.Bits.CapturedSlotPowerLimitValue + ); + ShellPrintEx (-1, -1, + L" Captured Slot Power Limit Scale(27:26): %E%s%N\r\n", + SlotPwrLmtScaleTable[PciExpressCap->DeviceCapability.Bits.CapturedSlotPowerLimitScale] + ); + } + // + // Function Level Reset Capability is only valid for Endpoint + // + if (IS_PCIE_ENDPOINT (DevicePortType)) { + ShellPrintEx (-1, -1, + L" Function Level Reset Capability(28): %E%d%N\r\n", + PciExpressCap->DeviceCapability.Bits.FunctionLevelReset + ); + } + return EFI_SUCCESS; +} + +/** + Print out information of the device control information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieDeviceControl ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ) +{ + ShellPrintEx (-1, -1, + L" Correctable Error Reporting Enable(0): %E%d%N\r\n", + PciExpressCap->DeviceControl.Bits.CorrectableError + ); + ShellPrintEx (-1, -1, + L" Non-Fatal Error Reporting Enable(1): %E%d%N\r\n", + PciExpressCap->DeviceControl.Bits.NonFatalError + ); + ShellPrintEx (-1, -1, + L" Fatal Error Reporting Enable(2): %E%d%N\r\n", + PciExpressCap->DeviceControl.Bits.FatalError + ); + ShellPrintEx (-1, -1, + L" Unsupported Request Reporting Enable(3): %E%d%N\r\n", + PciExpressCap->DeviceControl.Bits.UnsupportedRequest + ); + ShellPrintEx (-1, -1, + L" Enable Relaxed Ordering(4): %E%d%N\r\n", + PciExpressCap->DeviceControl.Bits.RelaxedOrdering + ); + ShellPrintEx (-1, -1, L" Max_Payload_Size(7:5): "); + if (PciExpressCap->DeviceControl.Bits.MaxPayloadSize < 6) { + ShellPrintEx (-1, -1, L"%E%d bytes%N\r\n", 1 << (PciExpressCap->DeviceControl.Bits.MaxPayloadSize + 7)); + } else { + ShellPrintEx (-1, -1, L"%EUnknown%N\r\n"); + } + ShellPrintEx (-1, -1, + L" Extended Tag Field Enable(8): %E%d%N\r\n", + PciExpressCap->DeviceControl.Bits.ExtendedTagField + ); + ShellPrintEx (-1, -1, + L" Phantom Functions Enable(9): %E%d%N\r\n", + PciExpressCap->DeviceControl.Bits.PhantomFunctions + ); + ShellPrintEx (-1, -1, + L" Auxiliary (AUX) Power PM Enable(10): %E%d%N\r\n", + PciExpressCap->DeviceControl.Bits.AuxPower + ); + ShellPrintEx (-1, -1, + L" Enable No Snoop(11): %E%d%N\r\n", + PciExpressCap->DeviceControl.Bits.NoSnoop + ); + ShellPrintEx (-1, -1, L" Max_Read_Request_Size(14:12): "); + if (PciExpressCap->DeviceControl.Bits.MaxReadRequestSize < 6) { + ShellPrintEx (-1, -1, L"%E%d bytes%N\r\n", 1 << (PciExpressCap->DeviceControl.Bits.MaxReadRequestSize + 7)); + } else { + ShellPrintEx (-1, -1, L"%EUnknown%N\r\n"); + } + // + // Read operation is only valid for PCI Express to PCI/PCI-X Bridges + // + if (PciExpressCap->Capability.Bits.DevicePortType == PCIE_DEVICE_PORT_TYPE_PCIE_TO_PCI_BRIDGE) { + ShellPrintEx (-1, -1, + L" Bridge Configuration Retry Enable(15): %E%d%N\r\n", + PciExpressCap->DeviceControl.Bits.BridgeConfigurationRetryOrFunctionLevelReset + ); + } + return EFI_SUCCESS; +} + +/** + Print out information of the device status information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieDeviceStatus ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ) +{ + ShellPrintEx (-1, -1, + L" Correctable Error Detected(0): %E%d%N\r\n", + PciExpressCap->DeviceStatus.Bits.CorrectableError + ); + ShellPrintEx (-1, -1, + L" Non-Fatal Error Detected(1): %E%d%N\r\n", + PciExpressCap->DeviceStatus.Bits.NonFatalError + ); + ShellPrintEx (-1, -1, + L" Fatal Error Detected(2): %E%d%N\r\n", + PciExpressCap->DeviceStatus.Bits.FatalError + ); + ShellPrintEx (-1, -1, + L" Unsupported Request Detected(3): %E%d%N\r\n", + PciExpressCap->DeviceStatus.Bits.UnsupportedRequest + ); + ShellPrintEx (-1, -1, + L" AUX Power Detected(4): %E%d%N\r\n", + PciExpressCap->DeviceStatus.Bits.AuxPower + ); + ShellPrintEx (-1, -1, + L" Transactions Pending(5): %E%d%N\r\n", + PciExpressCap->DeviceStatus.Bits.TransactionsPending + ); + return EFI_SUCCESS; +} + +/** + Print out information of the device link information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieLinkCap ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ) +{ + CHAR16 *MaxLinkSpeed; + CHAR16 *AspmValue; + + switch (PciExpressCap->LinkCapability.Bits.MaxLinkSpeed) { + case 1: + MaxLinkSpeed = L"2.5 GT/s"; + break; + case 2: + MaxLinkSpeed = L"5.0 GT/s"; + break; + case 3: + MaxLinkSpeed = L"8.0 GT/s"; + break; + case 4: + MaxLinkSpeed = L"16.0 GT/s"; + break; + case 5: + MaxLinkSpeed = L"32.0 GT/s"; + break; + default: + MaxLinkSpeed = L"Reserved"; + break; + } + ShellPrintEx (-1, -1, + L" Maximum Link Speed(3:0): %E%s%N\r\n", + MaxLinkSpeed + ); + ShellPrintEx (-1, -1, + L" Maximum Link Width(9:4): %Ex%d%N\r\n", + PciExpressCap->LinkCapability.Bits.MaxLinkWidth + ); + switch (PciExpressCap->LinkCapability.Bits.Aspm) { + case 0: + AspmValue = L"Not"; + break; + case 1: + AspmValue = L"L0s"; + break; + case 2: + AspmValue = L"L1"; + break; + case 3: + AspmValue = L"L0s and L1"; + break; + default: + AspmValue = L"Reserved"; + break; + } + ShellPrintEx (-1, -1, + L" Active State Power Management Support(11:10): %E%s Supported%N\r\n", + AspmValue + ); + ShellPrintEx (-1, -1, + L" L0s Exit Latency(14:12): %E%s%N\r\n", + L0sLatencyStrTable[PciExpressCap->LinkCapability.Bits.L0sExitLatency] + ); + ShellPrintEx (-1, -1, + L" L1 Exit Latency(17:15): %E%s%N\r\n", + L1LatencyStrTable[PciExpressCap->LinkCapability.Bits.L1ExitLatency] + ); + ShellPrintEx (-1, -1, + L" Clock Power Management(18): %E%d%N\r\n", + PciExpressCap->LinkCapability.Bits.ClockPowerManagement + ); + ShellPrintEx (-1, -1, + L" Surprise Down Error Reporting Capable(19): %E%d%N\r\n", + PciExpressCap->LinkCapability.Bits.SurpriseDownError + ); + ShellPrintEx (-1, -1, + L" Data Link Layer Link Active Reporting Capable(20): %E%d%N\r\n", + PciExpressCap->LinkCapability.Bits.DataLinkLayerLinkActive + ); + ShellPrintEx (-1, -1, + L" Link Bandwidth Notification Capability(21): %E%d%N\r\n", + PciExpressCap->LinkCapability.Bits.LinkBandwidthNotification + ); + ShellPrintEx (-1, -1, + L" Port Number(31:24): %E0x%02x%N\r\n", + PciExpressCap->LinkCapability.Bits.PortNumber + ); + return EFI_SUCCESS; +} + +/** + Print out information of the device link control information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieLinkControl ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ) +{ + UINT8 DevicePortType; + + DevicePortType = (UINT8)PciExpressCap->Capability.Bits.DevicePortType; + ShellPrintEx (-1, -1, + L" Active State Power Management Control(1:0): %E%s%N\r\n", + ASPMCtrlStrTable[PciExpressCap->LinkControl.Bits.AspmControl] + ); + // + // RCB is not applicable to switches + // + if (!IS_PCIE_SWITCH(DevicePortType)) { + ShellPrintEx (-1, -1, + L" Read Completion Boundary (RCB)(3): %E%d byte%N\r\n", + 1 << (PciExpressCap->LinkControl.Bits.ReadCompletionBoundary + 6) + ); + } + // + // Link Disable is reserved on + // a) Endpoints + // b) PCI Express to PCI/PCI-X bridges + // c) Upstream Ports of Switches + // + if (!IS_PCIE_ENDPOINT (DevicePortType) && + DevicePortType != PCIE_DEVICE_PORT_TYPE_UPSTREAM_PORT && + DevicePortType != PCIE_DEVICE_PORT_TYPE_PCIE_TO_PCI_BRIDGE) { + ShellPrintEx (-1, -1, + L" Link Disable(4): %E%d%N\r\n", + PciExpressCap->LinkControl.Bits.LinkDisable + ); + } + ShellPrintEx (-1, -1, + L" Common Clock Configuration(6): %E%d%N\r\n", + PciExpressCap->LinkControl.Bits.CommonClockConfiguration + ); + ShellPrintEx (-1, -1, + L" Extended Synch(7): %E%d%N\r\n", + PciExpressCap->LinkControl.Bits.ExtendedSynch + ); + ShellPrintEx (-1, -1, + L" Enable Clock Power Management(8): %E%d%N\r\n", + PciExpressCap->LinkControl.Bits.ClockPowerManagement + ); + ShellPrintEx (-1, -1, + L" Hardware Autonomous Width Disable(9): %E%d%N\r\n", + PciExpressCap->LinkControl.Bits.HardwareAutonomousWidthDisable + ); + ShellPrintEx (-1, -1, + L" Link Bandwidth Management Interrupt Enable(10): %E%d%N\r\n", + PciExpressCap->LinkControl.Bits.LinkBandwidthManagementInterrupt + ); + ShellPrintEx (-1, -1, + L" Link Autonomous Bandwidth Interrupt Enable(11): %E%d%N\r\n", + PciExpressCap->LinkControl.Bits.LinkAutonomousBandwidthInterrupt + ); + return EFI_SUCCESS; +} + +/** + Print out information of the device link status information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieLinkStatus ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ) +{ + CHAR16 *CurLinkSpeed; + + switch (PciExpressCap->LinkStatus.Bits.CurrentLinkSpeed) { + case 1: + CurLinkSpeed = L"2.5 GT/s"; + break; + case 2: + CurLinkSpeed = L"5.0 GT/s"; + break; + case 3: + CurLinkSpeed = L"8.0 GT/s"; + break; + case 4: + CurLinkSpeed = L"16.0 GT/s"; + break; + case 5: + CurLinkSpeed = L"32.0 GT/s"; + break; + default: + CurLinkSpeed = L"Reserved"; + break; + } + ShellPrintEx (-1, -1, + L" Current Link Speed(3:0): %E%s%N\r\n", + CurLinkSpeed + ); + ShellPrintEx (-1, -1, + L" Negotiated Link Width(9:4): %Ex%d%N\r\n", + PciExpressCap->LinkStatus.Bits.NegotiatedLinkWidth + ); + ShellPrintEx (-1, -1, + L" Link Training(11): %E%d%N\r\n", + PciExpressCap->LinkStatus.Bits.LinkTraining + ); + ShellPrintEx (-1, -1, + L" Slot Clock Configuration(12): %E%d%N\r\n", + PciExpressCap->LinkStatus.Bits.SlotClockConfiguration + ); + ShellPrintEx (-1, -1, + L" Data Link Layer Link Active(13): %E%d%N\r\n", + PciExpressCap->LinkStatus.Bits.DataLinkLayerLinkActive + ); + ShellPrintEx (-1, -1, + L" Link Bandwidth Management Status(14): %E%d%N\r\n", + PciExpressCap->LinkStatus.Bits.LinkBandwidthManagement + ); + ShellPrintEx (-1, -1, + L" Link Autonomous Bandwidth Status(15): %E%d%N\r\n", + PciExpressCap->LinkStatus.Bits.LinkAutonomousBandwidth + ); + return EFI_SUCCESS; +} + +/** + Print out information of the device slot information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieSlotCap ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ) +{ + ShellPrintEx (-1, -1, + L" Attention Button Present(0): %E%d%N\r\n", + PciExpressCap->SlotCapability.Bits.AttentionButton + ); + ShellPrintEx (-1, -1, + L" Power Controller Present(1): %E%d%N\r\n", + PciExpressCap->SlotCapability.Bits.PowerController + ); + ShellPrintEx (-1, -1, + L" MRL Sensor Present(2): %E%d%N\r\n", + PciExpressCap->SlotCapability.Bits.MrlSensor + ); + ShellPrintEx (-1, -1, + L" Attention Indicator Present(3): %E%d%N\r\n", + PciExpressCap->SlotCapability.Bits.AttentionIndicator + ); + ShellPrintEx (-1, -1, + L" Power Indicator Present(4): %E%d%N\r\n", + PciExpressCap->SlotCapability.Bits.PowerIndicator + ); + ShellPrintEx (-1, -1, + L" Hot-Plug Surprise(5): %E%d%N\r\n", + PciExpressCap->SlotCapability.Bits.HotPlugSurprise + ); + ShellPrintEx (-1, -1, + L" Hot-Plug Capable(6): %E%d%N\r\n", + PciExpressCap->SlotCapability.Bits.HotPlugCapable + ); + ShellPrintEx (-1, -1, + L" Slot Power Limit Value(14:7): %E0x%02x%N\r\n", + PciExpressCap->SlotCapability.Bits.SlotPowerLimitValue + ); + ShellPrintEx (-1, -1, + L" Slot Power Limit Scale(16:15): %E%s%N\r\n", + SlotPwrLmtScaleTable[PciExpressCap->SlotCapability.Bits.SlotPowerLimitScale] + ); + ShellPrintEx (-1, -1, + L" Electromechanical Interlock Present(17): %E%d%N\r\n", + PciExpressCap->SlotCapability.Bits.ElectromechanicalInterlock + ); + ShellPrintEx (-1, -1, + L" No Command Completed Support(18): %E%d%N\r\n", + PciExpressCap->SlotCapability.Bits.NoCommandCompleted + ); + ShellPrintEx (-1, -1, + L" Physical Slot Number(31:19): %E%d%N\r\n", + PciExpressCap->SlotCapability.Bits.PhysicalSlotNumber + ); + + return EFI_SUCCESS; +} + +/** + Print out information of the device slot control information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieSlotControl ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ) +{ + ShellPrintEx (-1, -1, + L" Attention Button Pressed Enable(0): %E%d%N\r\n", + PciExpressCap->SlotControl.Bits.AttentionButtonPressed + ); + ShellPrintEx (-1, -1, + L" Power Fault Detected Enable(1): %E%d%N\r\n", + PciExpressCap->SlotControl.Bits.PowerFaultDetected + ); + ShellPrintEx (-1, -1, + L" MRL Sensor Changed Enable(2): %E%d%N\r\n", + PciExpressCap->SlotControl.Bits.MrlSensorChanged + ); + ShellPrintEx (-1, -1, + L" Presence Detect Changed Enable(3): %E%d%N\r\n", + PciExpressCap->SlotControl.Bits.PresenceDetectChanged + ); + ShellPrintEx (-1, -1, + L" Command Completed Interrupt Enable(4): %E%d%N\r\n", + PciExpressCap->SlotControl.Bits.CommandCompletedInterrupt + ); + ShellPrintEx (-1, -1, + L" Hot-Plug Interrupt Enable(5): %E%d%N\r\n", + PciExpressCap->SlotControl.Bits.HotPlugInterrupt + ); + ShellPrintEx (-1, -1, + L" Attention Indicator Control(7:6): %E%s%N\r\n", + IndicatorTable[ + PciExpressCap->SlotControl.Bits.AttentionIndicator] + ); + ShellPrintEx (-1, -1, + L" Power Indicator Control(9:8): %E%s%N\r\n", + IndicatorTable[PciExpressCap->SlotControl.Bits.PowerIndicator] + ); + ShellPrintEx (-1, -1, L" Power Controller Control(10): %EPower "); + if ( + PciExpressCap->SlotControl.Bits.PowerController) { + ShellPrintEx (-1, -1, L"Off%N\r\n"); + } else { + ShellPrintEx (-1, -1, L"On%N\r\n"); + } + ShellPrintEx (-1, -1, + L" Electromechanical Interlock Control(11): %E%d%N\r\n", + PciExpressCap->SlotControl.Bits.ElectromechanicalInterlock + ); + ShellPrintEx (-1, -1, + L" Data Link Layer State Changed Enable(12): %E%d%N\r\n", + PciExpressCap->SlotControl.Bits.DataLinkLayerStateChanged + ); + return EFI_SUCCESS; +} + +/** + Print out information of the device slot status information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieSlotStatus ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ) +{ + ShellPrintEx (-1, -1, + L" Attention Button Pressed(0): %E%d%N\r\n", + PciExpressCap->SlotStatus.Bits.AttentionButtonPressed + ); + ShellPrintEx (-1, -1, + L" Power Fault Detected(1): %E%d%N\r\n", + PciExpressCap->SlotStatus.Bits.PowerFaultDetected + ); + ShellPrintEx (-1, -1, + L" MRL Sensor Changed(2): %E%d%N\r\n", + PciExpressCap->SlotStatus.Bits.MrlSensorChanged + ); + ShellPrintEx (-1, -1, + L" Presence Detect Changed(3): %E%d%N\r\n", + PciExpressCap->SlotStatus.Bits.PresenceDetectChanged + ); + ShellPrintEx (-1, -1, + L" Command Completed(4): %E%d%N\r\n", + PciExpressCap->SlotStatus.Bits.CommandCompleted + ); + ShellPrintEx (-1, -1, L" MRL Sensor State(5): %EMRL "); + if ( + PciExpressCap->SlotStatus.Bits.MrlSensor) { + ShellPrintEx (-1, -1, L" Opened%N\r\n"); + } else { + ShellPrintEx (-1, -1, L" Closed%N\r\n"); + } + ShellPrintEx (-1, -1, L" Presence Detect State(6): "); + if ( + PciExpressCap->SlotStatus.Bits.PresenceDetect) { + ShellPrintEx (-1, -1, L"%ECard Present in slot%N\r\n"); + } else { + ShellPrintEx (-1, -1, L"%ESlot Empty%N\r\n"); + } + ShellPrintEx (-1, -1, L" Electromechanical Interlock Status(7): %EElectromechanical Interlock "); + if ( + PciExpressCap->SlotStatus.Bits.ElectromechanicalInterlock) { + ShellPrintEx (-1, -1, L"Engaged%N\r\n"); + } else { + ShellPrintEx (-1, -1, L"Disengaged%N\r\n"); + } + ShellPrintEx (-1, -1, + L" Data Link Layer State Changed(8): %E%d%N\r\n", + PciExpressCap->SlotStatus.Bits.DataLinkLayerStateChanged + ); + return EFI_SUCCESS; +} + +/** + Print out information of the device root information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieRootControl ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ) +{ + ShellPrintEx (-1, -1, + L" System Error on Correctable Error Enable(0): %E%d%N\r\n", + PciExpressCap->RootControl.Bits.SystemErrorOnCorrectableError + ); + ShellPrintEx (-1, -1, + L" System Error on Non-Fatal Error Enable(1): %E%d%N\r\n", + PciExpressCap->RootControl.Bits.SystemErrorOnNonFatalError + ); + ShellPrintEx (-1, -1, + L" System Error on Fatal Error Enable(2): %E%d%N\r\n", + PciExpressCap->RootControl.Bits.SystemErrorOnFatalError + ); + ShellPrintEx (-1, -1, + L" PME Interrupt Enable(3): %E%d%N\r\n", + PciExpressCap->RootControl.Bits.PmeInterrupt + ); + ShellPrintEx (-1, -1, + L" CRS Software Visibility Enable(4): %E%d%N\r\n", + PciExpressCap->RootControl.Bits.CrsSoftwareVisibility + ); + + return EFI_SUCCESS; +} + +/** + Print out information of the device root capability information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieRootCap ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ) +{ + ShellPrintEx (-1, -1, + L" CRS Software Visibility(0): %E%d%N\r\n", + PciExpressCap->RootCapability.Bits.CrsSoftwareVisibility + ); + + return EFI_SUCCESS; +} + +/** + Print out information of the device root status information. + + @param[in] PciExpressCap The pointer to the structure about the device. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ExplainPcieRootStatus ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap + ) +{ + ShellPrintEx (-1, -1, + L" PME Requester ID(15:0): %E0x%04x%N\r\n", + PciExpressCap->RootStatus.Bits.PmeRequesterId + ); + ShellPrintEx (-1, -1, + L" PME Status(16): %E%d%N\r\n", + PciExpressCap->RootStatus.Bits.PmeStatus + ); + ShellPrintEx (-1, -1, + L" PME Pending(17): %E%d%N\r\n", + PciExpressCap->RootStatus.Bits.PmePending + ); + return EFI_SUCCESS; +} + +/** + Function to interpret and print out the link control structure + + @param[in] HeaderAddress The Address of this capability header. + @param[in] HeadersBaseAddress The address of all the extended capability headers. +**/ +EFI_STATUS +PrintInterpretedExtendedCompatibilityLinkControl ( + IN CONST PCI_EXP_EXT_HDR *HeaderAddress, + IN CONST PCI_EXP_EXT_HDR *HeadersBaseAddress + ) +{ + CONST PCI_EXPRESS_EXTENDED_CAPABILITIES_INTERNAL_LINK_CONTROL *Header; + Header = (PCI_EXPRESS_EXTENDED_CAPABILITIES_INTERNAL_LINK_CONTROL*)HeaderAddress; + + ShellPrintHiiEx( + -1, -1, NULL, + STRING_TOKEN (STR_PCI_EXT_CAP_LINK_CONTROL), + gShellDebug1HiiHandle, + Header->RootComplexLinkCapabilities, + Header->RootComplexLinkControl, + Header->RootComplexLinkStatus + ); + DumpHex ( + 4, + EFI_PCIE_CAPABILITY_BASE_OFFSET + ((UINT8*)HeaderAddress - (UINT8*)HeadersBaseAddress), + sizeof(PCI_EXPRESS_EXTENDED_CAPABILITIES_INTERNAL_LINK_CONTROL), + (VOID *) (HeaderAddress) + ); + return (EFI_SUCCESS); +} + +/** + Function to interpret and print out the power budgeting structure + + @param[in] HeaderAddress The Address of this capability header. + @param[in] HeadersBaseAddress The address of all the extended capability headers. +**/ +EFI_STATUS +PrintInterpretedExtendedCompatibilityPowerBudgeting ( + IN CONST PCI_EXP_EXT_HDR *HeaderAddress, + IN CONST PCI_EXP_EXT_HDR *HeadersBaseAddress + ) +{ + CONST PCI_EXPRESS_EXTENDED_CAPABILITIES_POWER_BUDGETING *Header; + Header = (PCI_EXPRESS_EXTENDED_CAPABILITIES_POWER_BUDGETING*)HeaderAddress; + + ShellPrintHiiEx( + -1, -1, NULL, + STRING_TOKEN (STR_PCI_EXT_CAP_POWER), + gShellDebug1HiiHandle, + Header->DataSelect, + Header->Data, + Header->PowerBudgetCapability + ); + DumpHex ( + 4, + EFI_PCIE_CAPABILITY_BASE_OFFSET + ((UINT8*)HeaderAddress - (UINT8*)HeadersBaseAddress), + sizeof(PCI_EXPRESS_EXTENDED_CAPABILITIES_POWER_BUDGETING), + (VOID *) (HeaderAddress) + ); + return (EFI_SUCCESS); +} + +/** + Function to interpret and print out the ACS structure + + @param[in] HeaderAddress The Address of this capability header. + @param[in] HeadersBaseAddress The address of all the extended capability headers. +**/ +EFI_STATUS +PrintInterpretedExtendedCompatibilityAcs ( + IN CONST PCI_EXP_EXT_HDR *HeaderAddress, + IN CONST PCI_EXP_EXT_HDR *HeadersBaseAddress + ) +{ + CONST PCI_EXPRESS_EXTENDED_CAPABILITIES_ACS_EXTENDED *Header; + UINT16 VectorSize; + UINT16 LoopCounter; + + Header = (PCI_EXPRESS_EXTENDED_CAPABILITIES_ACS_EXTENDED*)HeaderAddress; + VectorSize = 0; + + ShellPrintHiiEx( + -1, -1, NULL, + STRING_TOKEN (STR_PCI_EXT_CAP_ACS), + gShellDebug1HiiHandle, + Header->AcsCapability, + Header->AcsControl + ); + if (PCI_EXPRESS_EXTENDED_CAPABILITY_ACS_EXTENDED_GET_EGRES_CONTROL(Header)) { + VectorSize = PCI_EXPRESS_EXTENDED_CAPABILITY_ACS_EXTENDED_GET_EGRES_VECTOR_SIZE(Header); + if (VectorSize == 0) { + VectorSize = 256; + } + for (LoopCounter = 0 ; LoopCounter * 8 < VectorSize ; LoopCounter++) { + ShellPrintHiiEx( + -1, -1, NULL, + STRING_TOKEN (STR_PCI_EXT_CAP_ACS2), + gShellDebug1HiiHandle, + LoopCounter + 1, + Header->EgressControlVectorArray[LoopCounter] + ); + } + } + DumpHex ( + 4, + EFI_PCIE_CAPABILITY_BASE_OFFSET + ((UINT8*)HeaderAddress - (UINT8*)HeadersBaseAddress), + sizeof(PCI_EXPRESS_EXTENDED_CAPABILITIES_ACS_EXTENDED) + (VectorSize / 8) - 1, + (VOID *) (HeaderAddress) + ); + return (EFI_SUCCESS); +} + +/** + Function to interpret and print out the latency tolerance reporting structure + + @param[in] HeaderAddress The Address of this capability header. + @param[in] HeadersBaseAddress The address of all the extended capability headers. +**/ +EFI_STATUS +PrintInterpretedExtendedCompatibilityLatencyToleranceReporting ( + IN CONST PCI_EXP_EXT_HDR *HeaderAddress, + IN CONST PCI_EXP_EXT_HDR *HeadersBaseAddress + ) +{ + CONST PCI_EXPRESS_EXTENDED_CAPABILITIES_LATENCE_TOLERANCE_REPORTING *Header; + Header = (PCI_EXPRESS_EXTENDED_CAPABILITIES_LATENCE_TOLERANCE_REPORTING*)HeaderAddress; + + ShellPrintHiiEx( + -1, -1, NULL, + STRING_TOKEN (STR_PCI_EXT_CAP_LAT), + gShellDebug1HiiHandle, + Header->MaxSnoopLatency, + Header->MaxNoSnoopLatency + ); + DumpHex ( + 4, + EFI_PCIE_CAPABILITY_BASE_OFFSET + ((UINT8*)HeaderAddress - (UINT8*)HeadersBaseAddress), + sizeof(PCI_EXPRESS_EXTENDED_CAPABILITIES_LATENCE_TOLERANCE_REPORTING), + (VOID *) (HeaderAddress) + ); + return (EFI_SUCCESS); +} + +/** + Function to interpret and print out the serial number structure + + @param[in] HeaderAddress The Address of this capability header. + @param[in] HeadersBaseAddress The address of all the extended capability headers. +**/ +EFI_STATUS +PrintInterpretedExtendedCompatibilitySerialNumber ( + IN CONST PCI_EXP_EXT_HDR *HeaderAddress, + IN CONST PCI_EXP_EXT_HDR *HeadersBaseAddress + ) +{ + CONST PCI_EXPRESS_EXTENDED_CAPABILITIES_SERIAL_NUMBER *Header; + Header = (PCI_EXPRESS_EXTENDED_CAPABILITIES_SERIAL_NUMBER*)HeaderAddress; + + ShellPrintHiiEx( + -1, -1, NULL, + STRING_TOKEN (STR_PCI_EXT_CAP_SN), + gShellDebug1HiiHandle, + Header->SerialNumber + ); + DumpHex ( + 4, + EFI_PCIE_CAPABILITY_BASE_OFFSET + ((UINT8*)HeaderAddress - (UINT8*)HeadersBaseAddress), + sizeof(PCI_EXPRESS_EXTENDED_CAPABILITIES_SERIAL_NUMBER), + (VOID *) (HeaderAddress) + ); + return (EFI_SUCCESS); +} + +/** + Function to interpret and print out the RCRB structure + + @param[in] HeaderAddress The Address of this capability header. + @param[in] HeadersBaseAddress The address of all the extended capability headers. +**/ +EFI_STATUS +PrintInterpretedExtendedCompatibilityRcrb ( + IN CONST PCI_EXP_EXT_HDR *HeaderAddress, + IN CONST PCI_EXP_EXT_HDR *HeadersBaseAddress + ) +{ + CONST PCI_EXPRESS_EXTENDED_CAPABILITIES_RCRB_HEADER *Header; + Header = (PCI_EXPRESS_EXTENDED_CAPABILITIES_RCRB_HEADER*)HeaderAddress; + + ShellPrintHiiEx( + -1, -1, NULL, + STRING_TOKEN (STR_PCI_EXT_CAP_RCRB), + gShellDebug1HiiHandle, + Header->VendorId, + Header->DeviceId, + Header->RcrbCapabilities, + Header->RcrbControl + ); + DumpHex ( + 4, + EFI_PCIE_CAPABILITY_BASE_OFFSET + ((UINT8*)HeaderAddress - (UINT8*)HeadersBaseAddress), + sizeof(PCI_EXPRESS_EXTENDED_CAPABILITIES_RCRB_HEADER), + (VOID *) (HeaderAddress) + ); + return (EFI_SUCCESS); +} + +/** + Function to interpret and print out the vendor specific structure + + @param[in] HeaderAddress The Address of this capability header. + @param[in] HeadersBaseAddress The address of all the extended capability headers. +**/ +EFI_STATUS +PrintInterpretedExtendedCompatibilityVendorSpecific ( + IN CONST PCI_EXP_EXT_HDR *HeaderAddress, + IN CONST PCI_EXP_EXT_HDR *HeadersBaseAddress + ) +{ + CONST PCI_EXPRESS_EXTENDED_CAPABILITIES_VENDOR_SPECIFIC *Header; + Header = (PCI_EXPRESS_EXTENDED_CAPABILITIES_VENDOR_SPECIFIC*)HeaderAddress; + + ShellPrintHiiEx( + -1, -1, NULL, + STRING_TOKEN (STR_PCI_EXT_CAP_VEN), + gShellDebug1HiiHandle, + Header->VendorSpecificHeader + ); + DumpHex ( + 4, + EFI_PCIE_CAPABILITY_BASE_OFFSET + ((UINT8*)HeaderAddress - (UINT8*)HeadersBaseAddress), + PCI_EXPRESS_EXTENDED_CAPABILITY_VENDOR_SPECIFIC_GET_SIZE(Header), + (VOID *) (HeaderAddress) + ); + return (EFI_SUCCESS); +} + +/** + Function to interpret and print out the Event Collector Endpoint Association structure + + @param[in] HeaderAddress The Address of this capability header. + @param[in] HeadersBaseAddress The address of all the extended capability headers. +**/ +EFI_STATUS +PrintInterpretedExtendedCompatibilityECEA ( + IN CONST PCI_EXP_EXT_HDR *HeaderAddress, + IN CONST PCI_EXP_EXT_HDR *HeadersBaseAddress + ) +{ + CONST PCI_EXPRESS_EXTENDED_CAPABILITIES_EVENT_COLLECTOR_ENDPOINT_ASSOCIATION *Header; + Header = (PCI_EXPRESS_EXTENDED_CAPABILITIES_EVENT_COLLECTOR_ENDPOINT_ASSOCIATION*)HeaderAddress; + + ShellPrintHiiEx( + -1, -1, NULL, + STRING_TOKEN (STR_PCI_EXT_CAP_ECEA), + gShellDebug1HiiHandle, + Header->AssociationBitmap + ); + DumpHex ( + 4, + EFI_PCIE_CAPABILITY_BASE_OFFSET + ((UINT8*)HeaderAddress - (UINT8*)HeadersBaseAddress), + sizeof(PCI_EXPRESS_EXTENDED_CAPABILITIES_EVENT_COLLECTOR_ENDPOINT_ASSOCIATION), + (VOID *) (HeaderAddress) + ); + return (EFI_SUCCESS); +} + +/** + Function to interpret and print out the ARI structure + + @param[in] HeaderAddress The Address of this capability header. + @param[in] HeadersBaseAddress The address of all the extended capability headers. +**/ +EFI_STATUS +PrintInterpretedExtendedCompatibilityAri ( + IN CONST PCI_EXP_EXT_HDR *HeaderAddress, + IN CONST PCI_EXP_EXT_HDR *HeadersBaseAddress + ) +{ + CONST PCI_EXPRESS_EXTENDED_CAPABILITIES_ARI_CAPABILITY *Header; + Header = (PCI_EXPRESS_EXTENDED_CAPABILITIES_ARI_CAPABILITY*)HeaderAddress; + + ShellPrintHiiEx( + -1, -1, NULL, + STRING_TOKEN (STR_PCI_EXT_CAP_ARI), + gShellDebug1HiiHandle, + Header->AriCapability, + Header->AriControl + ); + DumpHex ( + 4, + EFI_PCIE_CAPABILITY_BASE_OFFSET + ((UINT8*)HeaderAddress - (UINT8*)HeadersBaseAddress), + sizeof(PCI_EXPRESS_EXTENDED_CAPABILITIES_ARI_CAPABILITY), + (VOID *) (HeaderAddress) + ); + return (EFI_SUCCESS); +} + +/** + Function to interpret and print out the DPA structure + + @param[in] HeaderAddress The Address of this capability header. + @param[in] HeadersBaseAddress The address of all the extended capability headers. +**/ +EFI_STATUS +PrintInterpretedExtendedCompatibilityDynamicPowerAllocation ( + IN CONST PCI_EXP_EXT_HDR *HeaderAddress, + IN CONST PCI_EXP_EXT_HDR *HeadersBaseAddress + ) +{ + CONST PCI_EXPRESS_EXTENDED_CAPABILITIES_DYNAMIC_POWER_ALLOCATION *Header; + UINT8 LinkCount; + Header = (PCI_EXPRESS_EXTENDED_CAPABILITIES_DYNAMIC_POWER_ALLOCATION*)HeaderAddress; + + ShellPrintHiiEx( + -1, -1, NULL, + STRING_TOKEN (STR_PCI_EXT_CAP_DPA), + gShellDebug1HiiHandle, + Header->DpaCapability, + Header->DpaLatencyIndicator, + Header->DpaStatus, + Header->DpaControl + ); + for (LinkCount = 0 ; LinkCount < PCI_EXPRESS_EXTENDED_CAPABILITY_DYNAMIC_POWER_ALLOCATION_GET_SUBSTATE_MAX(Header) + 1 ; LinkCount++) { + ShellPrintHiiEx( + -1, -1, NULL, + STRING_TOKEN (STR_PCI_EXT_CAP_DPA2), + gShellDebug1HiiHandle, + LinkCount+1, + Header->DpaPowerAllocationArray[LinkCount] + ); + } + DumpHex ( + 4, + EFI_PCIE_CAPABILITY_BASE_OFFSET + ((UINT8*)HeaderAddress - (UINT8*)HeadersBaseAddress), + sizeof(PCI_EXPRESS_EXTENDED_CAPABILITIES_DYNAMIC_POWER_ALLOCATION) - 1 + PCI_EXPRESS_EXTENDED_CAPABILITY_DYNAMIC_POWER_ALLOCATION_GET_SUBSTATE_MAX(Header), + (VOID *) (HeaderAddress) + ); + return (EFI_SUCCESS); +} + +/** + Function to interpret and print out the link declaration structure + + @param[in] HeaderAddress The Address of this capability header. + @param[in] HeadersBaseAddress The address of all the extended capability headers. +**/ +EFI_STATUS +PrintInterpretedExtendedCompatibilityLinkDeclaration ( + IN CONST PCI_EXP_EXT_HDR *HeaderAddress, + IN CONST PCI_EXP_EXT_HDR *HeadersBaseAddress + ) +{ + CONST PCI_EXPRESS_EXTENDED_CAPABILITIES_LINK_DECLARATION *Header; + UINT8 LinkCount; + Header = (PCI_EXPRESS_EXTENDED_CAPABILITIES_LINK_DECLARATION*)HeaderAddress; + + ShellPrintHiiEx( + -1, -1, NULL, + STRING_TOKEN (STR_PCI_EXT_CAP_LINK_DECLAR), + gShellDebug1HiiHandle, + Header->ElementSelfDescription + ); + + for (LinkCount = 0 ; LinkCount < PCI_EXPRESS_EXTENDED_CAPABILITY_LINK_DECLARATION_GET_LINK_COUNT(Header) ; LinkCount++) { + ShellPrintHiiEx( + -1, -1, NULL, + STRING_TOKEN (STR_PCI_EXT_CAP_LINK_DECLAR2), + gShellDebug1HiiHandle, + LinkCount+1, + Header->LinkEntry[LinkCount] + ); + } + DumpHex ( + 4, + EFI_PCIE_CAPABILITY_BASE_OFFSET + ((UINT8*)HeaderAddress - (UINT8*)HeadersBaseAddress), + sizeof(PCI_EXPRESS_EXTENDED_CAPABILITIES_LINK_DECLARATION) + (PCI_EXPRESS_EXTENDED_CAPABILITY_LINK_DECLARATION_GET_LINK_COUNT(Header)-1)*sizeof(UINT32), + (VOID *) (HeaderAddress) + ); + return (EFI_SUCCESS); +} + +/** + Function to interpret and print out the Advanced Error Reporting structure + + @param[in] HeaderAddress The Address of this capability header. + @param[in] HeadersBaseAddress The address of all the extended capability headers. +**/ +EFI_STATUS +PrintInterpretedExtendedCompatibilityAer ( + IN CONST PCI_EXP_EXT_HDR *HeaderAddress, + IN CONST PCI_EXP_EXT_HDR *HeadersBaseAddress + ) +{ + CONST PCI_EXPRESS_EXTENDED_CAPABILITIES_ADVANCED_ERROR_REPORTING *Header; + Header = (PCI_EXPRESS_EXTENDED_CAPABILITIES_ADVANCED_ERROR_REPORTING*)HeaderAddress; + + ShellPrintHiiEx( + -1, -1, NULL, + STRING_TOKEN (STR_PCI_EXT_CAP_AER), + gShellDebug1HiiHandle, + Header->UncorrectableErrorStatus, + Header->UncorrectableErrorMask, + Header->UncorrectableErrorSeverity, + Header->CorrectableErrorStatus, + Header->CorrectableErrorMask, + Header->AdvancedErrorCapabilitiesAndControl, + Header->HeaderLog[0], + Header->HeaderLog[1], + Header->HeaderLog[2], + Header->HeaderLog[3], + Header->RootErrorCommand, + Header->RootErrorStatus, + Header->ErrorSourceIdentification, + Header->CorrectableErrorSourceIdentification, + Header->TlpPrefixLog[0], + Header->TlpPrefixLog[1], + Header->TlpPrefixLog[2], + Header->TlpPrefixLog[3] + ); + DumpHex ( + 4, + EFI_PCIE_CAPABILITY_BASE_OFFSET + ((UINT8*)HeaderAddress - (UINT8*)HeadersBaseAddress), + sizeof(PCI_EXPRESS_EXTENDED_CAPABILITIES_ADVANCED_ERROR_REPORTING), + (VOID *) (HeaderAddress) + ); + return (EFI_SUCCESS); +} + +/** + Function to interpret and print out the multicast structure + + @param[in] HeaderAddress The Address of this capability header. + @param[in] HeadersBaseAddress The address of all the extended capability headers. + @param[in] PciExpressCapPtr The address of the PCIe capabilities structure. +**/ +EFI_STATUS +PrintInterpretedExtendedCompatibilityMulticast ( + IN CONST PCI_EXP_EXT_HDR *HeaderAddress, + IN CONST PCI_EXP_EXT_HDR *HeadersBaseAddress, + IN CONST PCI_CAPABILITY_PCIEXP *PciExpressCapPtr + ) +{ + CONST PCI_EXPRESS_EXTENDED_CAPABILITIES_MULTICAST *Header; + Header = (PCI_EXPRESS_EXTENDED_CAPABILITIES_MULTICAST*)HeaderAddress; + + ShellPrintHiiEx( + -1, -1, NULL, + STRING_TOKEN (STR_PCI_EXT_CAP_MULTICAST), + gShellDebug1HiiHandle, + Header->MultiCastCapability, + Header->MulticastControl, + Header->McBaseAddress, + Header->McReceiveAddress, + Header->McBlockAll, + Header->McBlockUntranslated, + Header->McOverlayBar + ); + + DumpHex ( + 4, + EFI_PCIE_CAPABILITY_BASE_OFFSET + ((UINT8*)HeaderAddress - (UINT8*)HeadersBaseAddress), + sizeof(PCI_EXPRESS_EXTENDED_CAPABILITIES_MULTICAST), + (VOID *) (HeaderAddress) + ); + + return (EFI_SUCCESS); +} + +/** + Function to interpret and print out the virtual channel and multi virtual channel structure + + @param[in] HeaderAddress The Address of this capability header. + @param[in] HeadersBaseAddress The address of all the extended capability headers. +**/ +EFI_STATUS +PrintInterpretedExtendedCompatibilityVirtualChannel ( + IN CONST PCI_EXP_EXT_HDR *HeaderAddress, + IN CONST PCI_EXP_EXT_HDR *HeadersBaseAddress + ) +{ + CONST PCI_EXPRESS_EXTENDED_CAPABILITIES_VIRTUAL_CHANNEL_CAPABILITY *Header; + CONST PCI_EXPRESS_EXTENDED_CAPABILITIES_VIRTUAL_CHANNEL_VC *CapabilityItem; + UINT32 ItemCount; + Header = (PCI_EXPRESS_EXTENDED_CAPABILITIES_VIRTUAL_CHANNEL_CAPABILITY*)HeaderAddress; + + ShellPrintHiiEx( + -1, -1, NULL, + STRING_TOKEN (STR_PCI_EXT_CAP_VC_BASE), + gShellDebug1HiiHandle, + Header->ExtendedVcCount, + Header->PortVcCapability1, + Header->PortVcCapability2, + Header->VcArbTableOffset, + Header->PortVcControl, + Header->PortVcStatus + ); + for (ItemCount = 0 ; ItemCount < Header->ExtendedVcCount ; ItemCount++) { + CapabilityItem = &Header->Capability[ItemCount]; + ShellPrintHiiEx( + -1, -1, NULL, + STRING_TOKEN (STR_PCI_EXT_CAP_VC_ITEM), + gShellDebug1HiiHandle, + ItemCount+1, + CapabilityItem->VcResourceCapability, + CapabilityItem->PortArbTableOffset, + CapabilityItem->VcResourceControl, + CapabilityItem->VcResourceStatus + ); + } + + DumpHex ( + 4, + EFI_PCIE_CAPABILITY_BASE_OFFSET + ((UINT8*)HeaderAddress - (UINT8*)HeadersBaseAddress), + sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_VIRTUAL_CHANNEL_CAPABILITY) + + Header->ExtendedVcCount * sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_VIRTUAL_CHANNEL_VC), + (VOID *) (HeaderAddress) + ); + + return (EFI_SUCCESS); +} + +/** + Function to interpret and print out the resizeable bar structure + + @param[in] HeaderAddress The Address of this capability header. + @param[in] HeadersBaseAddress The address of all the extended capability headers. +**/ +EFI_STATUS +PrintInterpretedExtendedCompatibilityResizeableBar ( + IN CONST PCI_EXP_EXT_HDR *HeaderAddress, + IN CONST PCI_EXP_EXT_HDR *HeadersBaseAddress + ) +{ + CONST PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR *Header; + UINT32 ItemCount; + Header = (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR*)HeaderAddress; + + for (ItemCount = 0 ; ItemCount < (UINT32)GET_NUMBER_RESIZABLE_BARS(Header) ; ItemCount++) { + ShellPrintHiiEx( + -1, -1, NULL, + STRING_TOKEN (STR_PCI_EXT_CAP_RESIZE_BAR), + gShellDebug1HiiHandle, + ItemCount+1, + Header->Capability[ItemCount].ResizableBarCapability.Uint32, + Header->Capability[ItemCount].ResizableBarControl.Uint32 + ); + } + + DumpHex ( + 4, + EFI_PCIE_CAPABILITY_BASE_OFFSET + ((UINT8*)HeaderAddress - (UINT8*)HeadersBaseAddress), + (UINT32)GET_NUMBER_RESIZABLE_BARS(Header) * sizeof(PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_ENTRY), + (VOID *) (HeaderAddress) + ); + + return (EFI_SUCCESS); +} + +/** + Function to interpret and print out the TPH structure + + @param[in] HeaderAddress The Address of this capability header. + @param[in] HeadersBaseAddress The address of all the extended capability headers. +**/ +EFI_STATUS +PrintInterpretedExtendedCompatibilityTph ( + IN CONST PCI_EXP_EXT_HDR *HeaderAddress, + IN CONST PCI_EXP_EXT_HDR *HeadersBaseAddress + ) +{ + CONST PCI_EXPRESS_EXTENDED_CAPABILITIES_TPH *Header; + Header = (PCI_EXPRESS_EXTENDED_CAPABILITIES_TPH*)HeaderAddress; + + ShellPrintHiiEx( + -1, -1, NULL, + STRING_TOKEN (STR_PCI_EXT_CAP_TPH), + gShellDebug1HiiHandle, + Header->TphRequesterCapability, + Header->TphRequesterControl + ); + DumpHex ( + 8, + EFI_PCIE_CAPABILITY_BASE_OFFSET + ((UINT8*)Header->TphStTable - (UINT8*)HeadersBaseAddress), + GET_TPH_TABLE_SIZE(Header), + (VOID *)Header->TphStTable + ); + + DumpHex ( + 4, + EFI_PCIE_CAPABILITY_BASE_OFFSET + ((UINT8*)HeaderAddress - (UINT8*)HeadersBaseAddress), + sizeof(PCI_EXPRESS_EXTENDED_CAPABILITIES_TPH) + GET_TPH_TABLE_SIZE(Header) - sizeof(UINT16), + (VOID *) (HeaderAddress) + ); + + return (EFI_SUCCESS); +} + +/** + Function to interpret and print out the secondary PCIe capability structure + + @param[in] HeaderAddress The Address of this capability header. + @param[in] HeadersBaseAddress The address of all the extended capability headers. + @param[in] PciExpressCapPtr The address of the PCIe capabilities structure. +**/ +EFI_STATUS +PrintInterpretedExtendedCompatibilitySecondary ( + IN CONST PCI_EXP_EXT_HDR *HeaderAddress, + IN CONST PCI_EXP_EXT_HDR *HeadersBaseAddress, + IN CONST PCI_CAPABILITY_PCIEXP *PciExpressCap + ) +{ + CONST PCI_EXPRESS_EXTENDED_CAPABILITIES_SECONDARY_PCIE *Header; + Header = (PCI_EXPRESS_EXTENDED_CAPABILITIES_SECONDARY_PCIE*)HeaderAddress; + + ShellPrintHiiEx( + -1, -1, NULL, + STRING_TOKEN (STR_PCI_EXT_CAP_SECONDARY), + gShellDebug1HiiHandle, + Header->LinkControl3.Uint32, + Header->LaneErrorStatus + ); + DumpHex ( + 8, + EFI_PCIE_CAPABILITY_BASE_OFFSET + ((UINT8*)Header->EqualizationControl - (UINT8*)HeadersBaseAddress), + PciExpressCap->LinkCapability.Bits.MaxLinkWidth * sizeof (PCI_EXPRESS_REG_LANE_EQUALIZATION_CONTROL), + (VOID *)Header->EqualizationControl + ); + + DumpHex ( + 4, + EFI_PCIE_CAPABILITY_BASE_OFFSET + ((UINT8*)HeaderAddress - (UINT8*)HeadersBaseAddress), + sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_SECONDARY_PCIE) - sizeof (Header->EqualizationControl) + + PciExpressCap->LinkCapability.Bits.MaxLinkWidth * sizeof (PCI_EXPRESS_REG_LANE_EQUALIZATION_CONTROL), + (VOID *) (HeaderAddress) + ); + + return (EFI_SUCCESS); +} + +/** + Display Pcie extended capability details + + @param[in] HeadersBaseAddress The address of all the extended capability headers. + @param[in] HeaderAddress The address of this capability header. + @param[in] PciExpressCapPtr The address of the PCIe capabilities structure. +**/ +EFI_STATUS +PrintPciExtendedCapabilityDetails( + IN CONST PCI_EXP_EXT_HDR *HeadersBaseAddress, + IN CONST PCI_EXP_EXT_HDR *HeaderAddress, + IN CONST PCI_CAPABILITY_PCIEXP *PciExpressCapPtr + ) +{ + switch (HeaderAddress->CapabilityId){ + case PCI_EXPRESS_EXTENDED_CAPABILITY_ADVANCED_ERROR_REPORTING_ID: + return PrintInterpretedExtendedCompatibilityAer(HeaderAddress, HeadersBaseAddress); + case PCI_EXPRESS_EXTENDED_CAPABILITY_LINK_CONTROL_ID: + return PrintInterpretedExtendedCompatibilityLinkControl(HeaderAddress, HeadersBaseAddress); + case PCI_EXPRESS_EXTENDED_CAPABILITY_LINK_DECLARATION_ID: + return PrintInterpretedExtendedCompatibilityLinkDeclaration(HeaderAddress, HeadersBaseAddress); + case PCI_EXPRESS_EXTENDED_CAPABILITY_SERIAL_NUMBER_ID: + return PrintInterpretedExtendedCompatibilitySerialNumber(HeaderAddress, HeadersBaseAddress); + case PCI_EXPRESS_EXTENDED_CAPABILITY_POWER_BUDGETING_ID: + return PrintInterpretedExtendedCompatibilityPowerBudgeting(HeaderAddress, HeadersBaseAddress); + case PCI_EXPRESS_EXTENDED_CAPABILITY_ACS_EXTENDED_ID: + return PrintInterpretedExtendedCompatibilityAcs(HeaderAddress, HeadersBaseAddress); + case PCI_EXPRESS_EXTENDED_CAPABILITY_LATENCE_TOLERANCE_REPORTING_ID: + return PrintInterpretedExtendedCompatibilityLatencyToleranceReporting(HeaderAddress, HeadersBaseAddress); + case PCI_EXPRESS_EXTENDED_CAPABILITY_ARI_CAPABILITY_ID: + return PrintInterpretedExtendedCompatibilityAri(HeaderAddress, HeadersBaseAddress); + case PCI_EXPRESS_EXTENDED_CAPABILITY_RCRB_HEADER_ID: + return PrintInterpretedExtendedCompatibilityRcrb(HeaderAddress, HeadersBaseAddress); + case PCI_EXPRESS_EXTENDED_CAPABILITY_VENDOR_SPECIFIC_ID: + return PrintInterpretedExtendedCompatibilityVendorSpecific(HeaderAddress, HeadersBaseAddress); + case PCI_EXPRESS_EXTENDED_CAPABILITY_DYNAMIC_POWER_ALLOCATION_ID: + return PrintInterpretedExtendedCompatibilityDynamicPowerAllocation(HeaderAddress, HeadersBaseAddress); + case PCI_EXPRESS_EXTENDED_CAPABILITY_EVENT_COLLECTOR_ENDPOINT_ASSOCIATION_ID: + return PrintInterpretedExtendedCompatibilityECEA(HeaderAddress, HeadersBaseAddress); + case PCI_EXPRESS_EXTENDED_CAPABILITY_VIRTUAL_CHANNEL_ID: + case PCI_EXPRESS_EXTENDED_CAPABILITY_MULTI_FUNCTION_VIRTUAL_CHANNEL_ID: + return PrintInterpretedExtendedCompatibilityVirtualChannel(HeaderAddress, HeadersBaseAddress); + case PCI_EXPRESS_EXTENDED_CAPABILITY_MULTICAST_ID: + // + // should only be present if PCIE_CAP_DEVICEPORT_TYPE(PciExpressCapPtr->PcieCapReg) == 0100b, 0101b, or 0110b + // + return PrintInterpretedExtendedCompatibilityMulticast(HeaderAddress, HeadersBaseAddress, PciExpressCapPtr); + case PCI_EXPRESS_EXTENDED_CAPABILITY_RESIZABLE_BAR_ID: + return PrintInterpretedExtendedCompatibilityResizeableBar(HeaderAddress, HeadersBaseAddress); + case PCI_EXPRESS_EXTENDED_CAPABILITY_TPH_ID: + return PrintInterpretedExtendedCompatibilityTph(HeaderAddress, HeadersBaseAddress); + case PCI_EXPRESS_EXTENDED_CAPABILITY_SECONDARY_PCIE_ID: + return PrintInterpretedExtendedCompatibilitySecondary(HeaderAddress, HeadersBaseAddress, PciExpressCapPtr); + default: + ShellPrintEx (-1, -1, + L"Unknown PCIe extended capability ID (%04xh). No interpretation available.\r\n", + HeaderAddress->CapabilityId + ); + return EFI_SUCCESS; + }; + +} + +/** + Display Pcie device structure. + + @param[in] PciExpressCap PCI Express capability buffer. + @param[in] ExtendedConfigSpace PCI Express extended configuration space. + @param[in] ExtendedConfigSize PCI Express extended configuration size. + @param[in] ExtendedCapability PCI Express extended capability ID to explain. +**/ +VOID +PciExplainPciExpress ( + IN PCI_CAPABILITY_PCIEXP *PciExpressCap, + IN UINT8 *ExtendedConfigSpace, + IN UINTN ExtendedConfigSize, + IN CONST UINT16 ExtendedCapability + ) +{ + UINT8 DevicePortType; + UINTN Index; + UINT8 *RegAddr; + UINTN RegValue; + PCI_EXP_EXT_HDR *ExtHdr; + + DevicePortType = (UINT8)PciExpressCap->Capability.Bits.DevicePortType; + + ShellPrintEx (-1, -1, L"\r\nPci Express device capability structure:\r\n"); + + for (Index = 0; PcieExplainList[Index].Type < PcieExplainTypeMax; Index++) { + if (ShellGetExecutionBreakFlag()) { + return; + } + RegAddr = (UINT8 *) PciExpressCap + PcieExplainList[Index].Offset; + switch (PcieExplainList[Index].Width) { + case FieldWidthUINT8: + RegValue = *(UINT8 *) RegAddr; + break; + case FieldWidthUINT16: + RegValue = *(UINT16 *) RegAddr; + break; + case FieldWidthUINT32: + RegValue = *(UINT32 *) RegAddr; + break; + default: + RegValue = 0; + break; + } + ShellPrintHiiEx(-1, -1, NULL, + PcieExplainList[Index].Token, + gShellDebug1HiiHandle, + PcieExplainList[Index].Offset, + RegValue + ); + if (PcieExplainList[Index].Func == NULL) { + continue; + } + switch (PcieExplainList[Index].Type) { + case PcieExplainTypeLink: + // + // Link registers should not be used by + // a) Root Complex Integrated Endpoint + // b) Root Complex Event Collector + // + if (DevicePortType == PCIE_DEVICE_PORT_TYPE_ROOT_COMPLEX_INTEGRATED_ENDPOINT || + DevicePortType == PCIE_DEVICE_PORT_TYPE_ROOT_COMPLEX_EVENT_COLLECTOR) { + continue; + } + break; + case PcieExplainTypeSlot: + // + // Slot registers are only valid for + // a) Root Port of PCI Express Root Complex + // b) Downstream Port of PCI Express Switch + // and when SlotImplemented bit is set in PCIE cap register. + // + if ((DevicePortType != PCIE_DEVICE_PORT_TYPE_ROOT_PORT && + DevicePortType != PCIE_DEVICE_PORT_TYPE_DOWNSTREAM_PORT) || + !PciExpressCap->Capability.Bits.SlotImplemented) { + continue; + } + break; + case PcieExplainTypeRoot: + // + // Root registers are only valid for + // Root Port of PCI Express Root Complex + // + if (DevicePortType != PCIE_DEVICE_PORT_TYPE_ROOT_PORT) { + continue; + } + break; + default: + break; + } + PcieExplainList[Index].Func (PciExpressCap); + } + + ExtHdr = (PCI_EXP_EXT_HDR*)ExtendedConfigSpace; + while (ExtHdr->CapabilityId != 0 && ExtHdr->CapabilityVersion != 0 && ExtHdr->CapabilityId != 0xFFFF) { + // + // Process this item + // + if (ExtendedCapability == 0xFFFF || ExtendedCapability == ExtHdr->CapabilityId) { + // + // Print this item + // + PrintPciExtendedCapabilityDetails((PCI_EXP_EXT_HDR*)ExtendedConfigSpace, ExtHdr, PciExpressCap); + } + + // + // Advance to the next item if it exists + // + if (ExtHdr->NextCapabilityOffset != 0 && + (ExtHdr->NextCapabilityOffset <= (UINT32) (ExtendedConfigSize + EFI_PCIE_CAPABILITY_BASE_OFFSET - sizeof (PCI_EXP_EXT_HDR)))) { + ExtHdr = (PCI_EXP_EXT_HDR*)(ExtendedConfigSpace + ExtHdr->NextCapabilityOffset - EFI_PCIE_CAPABILITY_BASE_OFFSET); + } else { + break; + } + } +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Pci.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Pci.h new file mode 100644 index 00000000..3a7e1ad7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Pci.h @@ -0,0 +1,58 @@ +/** @file + Header file for Pci shell Debug1 function. + + Copyright (c) 2013 Hewlett-Packard Development Company, L.P. + Copyright (c) 2005 - 2017, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_SHELL_PCI_H_ +#define _EFI_SHELL_PCI_H_ + +typedef enum { + PciDevice, + PciP2pBridge, + PciCardBusBridge, + PciUndefined +} PCI_HEADER_TYPE; + +#define INDEX_OF(Field) ((UINT8 *) (Field) - (UINT8 *) mConfigSpace) + +#define IS_PCIE_ENDPOINT(DevicePortType) \ + ((DevicePortType) == PCIE_DEVICE_PORT_TYPE_PCIE_ENDPOINT || \ + (DevicePortType) == PCIE_DEVICE_PORT_TYPE_LEGACY_PCIE_ENDPOINT || \ + (DevicePortType) == PCIE_DEVICE_PORT_TYPE_ROOT_COMPLEX_INTEGRATED_ENDPOINT) + +#define IS_PCIE_SWITCH(DevicePortType) \ + ((DevicePortType == PCIE_DEVICE_PORT_TYPE_UPSTREAM_PORT) || \ + (DevicePortType == PCIE_DEVICE_PORT_TYPE_DOWNSTREAM_PORT)) + +#pragma pack(1) +// +// Data region after PCI configuration header(for cardbus bridge) +// +typedef struct { + UINT16 SubVendorId; // Subsystem Vendor ID + UINT16 SubSystemId; // Subsystem ID + UINT32 LegacyBase; // Optional 16-Bit PC Card Legacy + // Mode Base Address + // + UINT32 Data[46]; +} PCI_CARDBUS_DATA; + +typedef union { + PCI_DEVICE_HEADER_TYPE_REGION Device; + PCI_BRIDGE_CONTROL_REGISTER Bridge; + PCI_CARDBUS_CONTROL_REGISTER CardBus; +} NON_COMMON_UNION; + +typedef struct { + PCI_DEVICE_INDEPENDENT_REGION Common; + NON_COMMON_UNION NonCommon; + UINT32 Data[48]; +} PCI_CONFIG_SPACE; + +#pragma pack() + +#endif // _PCI_H_ diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SerMode.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SerMode.c new file mode 100644 index 00000000..c2955063 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SerMode.c @@ -0,0 +1,365 @@ +/** @file + Main file for SerMode shell Debug1 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDebug1CommandsLib.h" +#include +#include + +/** + Display information about a serial device by it's handle. + + If HandleValid is FALSE, do all devices. + + @param[in] HandleIdx The handle index for the device. + @param[in] HandleValid TRUE if HandleIdx is valid. + + @retval SHELL_INVALID_PARAMETER A parameter was invalid. + @retval SHELL_SUCCESS The operation was successful. +**/ +SHELL_STATUS +DisplaySettings ( + IN UINTN HandleIdx, + IN BOOLEAN HandleValid + ) +{ + EFI_SERIAL_IO_PROTOCOL *SerialIo; + UINTN NoHandles; + EFI_HANDLE *Handles; + EFI_STATUS Status; + UINTN Index; + CHAR16 *StopBits; + CHAR16 Parity; + SHELL_STATUS ShellStatus; + + Handles = NULL; + StopBits = NULL; + + ShellStatus = SHELL_SUCCESS; + + Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSerialIoProtocolGuid, NULL, &NoHandles, &Handles); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SERMODE_NO_FOUND), gShellDebug1HiiHandle, L"sermode"); + return SHELL_INVALID_PARAMETER; + } + + for (Index = 0; Index < NoHandles; Index++) { + if (HandleValid) { + if (ConvertHandleIndexToHandle(HandleIdx) != Handles[Index]) { + continue; + } + } + + Status = gBS->HandleProtocol (Handles[Index], &gEfiSerialIoProtocolGuid, (VOID**)&SerialIo); + if (!EFI_ERROR (Status)) { + switch (SerialIo->Mode->Parity) { + case DefaultParity: + + Parity = 'D'; + break; + + case NoParity: + + Parity = 'N'; + break; + + case EvenParity: + + Parity = 'E'; + break; + + case OddParity: + + Parity = 'O'; + break; + + case MarkParity: + + Parity = 'M'; + break; + + case SpaceParity: + + Parity = 'S'; + break; + + default: + + Parity = 'U'; + } + + switch (SerialIo->Mode->StopBits) { + case DefaultStopBits: + + StopBits = L"Default"; + break; + + case OneStopBit: + + StopBits = L"1"; + break; + + case TwoStopBits: + + StopBits = L"2"; + break; + + case OneFiveStopBits: + + StopBits = L"1.5"; + break; + + default: + + StopBits = L"Unknown"; + } + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_SERMODE_DISPLAY), + gShellDebug1HiiHandle, + ConvertHandleToHandleIndex (Handles[Index]), + Handles[Index], + SerialIo->Mode->BaudRate, + Parity, + SerialIo->Mode->DataBits, + StopBits + ); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SERMODE_NO_FOUND), gShellDebug1HiiHandle, L"sermode"); + ShellStatus = SHELL_NOT_FOUND; + break; + } + + if (HandleValid) { + break; + } + } + + if (Index == NoHandles) { + if ((NoHandles != 0 && HandleValid) || 0 == NoHandles) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SERMODE_NOT_FOUND), gShellDebug1HiiHandle, L"sermode"); + ShellStatus = SHELL_NOT_FOUND; + } + } + + return ShellStatus; +} + +/** + Function for 'sermode' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunSerMode ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + UINTN Index; + UINTN NoHandles; + EFI_HANDLE *Handles; + EFI_PARITY_TYPE Parity; + EFI_STOP_BITS_TYPE StopBits; + UINTN HandleIdx; + UINTN BaudRate; + UINTN DataBits; + UINTN Value; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + CONST CHAR16 *Temp; + UINT64 Intermediate; + + ShellStatus = SHELL_SUCCESS; + HandleIdx = 0; + Parity = DefaultParity; + Handles = NULL; + NoHandles = 0; + Index = 0; + Package = NULL; + + Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"sermode", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetCount(Package) < 6 && ShellCommandLineGetCount(Package) > 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"sermode"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetCount(Package) > 6) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"sermode"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Temp = ShellCommandLineGetRawValue(Package, 1); + if (Temp != NULL) { + Status = ShellConvertStringToUint64(Temp, &Intermediate, TRUE, FALSE); + HandleIdx = (UINTN)Intermediate; + Temp = ShellCommandLineGetRawValue(Package, 2); + if (Temp == NULL) { + ShellStatus = DisplaySettings (HandleIdx, TRUE); + goto Done; + } + } else { + ShellStatus = DisplaySettings (0, FALSE); + goto Done; + } + Temp = ShellCommandLineGetRawValue(Package, 2); + if (Temp != NULL) { + BaudRate = ShellStrToUintn(Temp); + } else { + ASSERT(FALSE); + BaudRate = 0; + } + Temp = ShellCommandLineGetRawValue(Package, 3); + if (Temp == NULL || StrLen(Temp)>1) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"sermode", Temp); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + switch(Temp[0]){ + case 'd': + case 'D': + Parity = DefaultParity; + break; + case 'n': + case 'N': + Parity = NoParity; + break; + case 'e': + case 'E': + Parity = EvenParity; + break; + case 'o': + case 'O': + Parity = OddParity; + break; + case 'm': + case 'M': + Parity = MarkParity; + break; + case 's': + case 'S': + Parity = SpaceParity; + break; + default: + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"sermode", Temp); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + } + Temp = ShellCommandLineGetRawValue(Package, 4); + if (Temp != NULL) { + DataBits = ShellStrToUintn(Temp); + } else { + // + // make sure this is some number not in the list below. + // + DataBits = 0; + } + switch (DataBits) { + case 4: + case 7: + case 8: + break; + default: + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"sermode", Temp); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + Temp = ShellCommandLineGetRawValue(Package, 5); + Value = ShellStrToUintn(Temp); + switch (Value) { + case 0: + StopBits = DefaultStopBits; + break; + + case 1: + StopBits = OneStopBit; + break; + + case 2: + StopBits = TwoStopBits; + break; + + case 15: + StopBits = OneFiveStopBits; + break; + + default: + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"sermode", Temp); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiSerialIoProtocolGuid, NULL, &NoHandles, &Handles); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SERMODE_NO_FOUND), gShellDebug1HiiHandle, L"sermode"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + + for (Index = 0; Index < NoHandles; Index++) { + if (ConvertHandleIndexToHandle (HandleIdx) != Handles[Index]) { + continue; + } + + Status = gBS->HandleProtocol (Handles[Index], &gEfiSerialIoProtocolGuid, (VOID**)&SerialIo); + if (!EFI_ERROR (Status)) { + Status = SerialIo->SetAttributes ( + SerialIo, + (UINT64) BaudRate, + SerialIo->Mode->ReceiveFifoDepth, + SerialIo->Mode->Timeout, + Parity, + (UINT8) DataBits, + StopBits + ); + if (EFI_ERROR (Status)) { + if (Status == EFI_INVALID_PARAMETER) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SERMODE_SET_UNSUPPORTED), gShellDebug1HiiHandle, L"sermode", ConvertHandleToHandleIndex(Handles[Index])); + ShellStatus = SHELL_UNSUPPORTED; + } else if (Status == EFI_DEVICE_ERROR) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SERMODE_SET_DEV_ERROR), gShellDebug1HiiHandle, L"sermode", ConvertHandleToHandleIndex(Handles[Index])); + ShellStatus = SHELL_ACCESS_DENIED; + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SERMODE_SET_FAIL), gShellDebug1HiiHandle, L"sermode", ConvertHandleToHandleIndex(Handles[Index])); + ShellStatus = SHELL_ACCESS_DENIED; + } + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SERMODE_SET_HANDLE), gShellDebug1HiiHandle, ConvertHandleToHandleIndex(Handles[Index])); + } + break; + } + } + } + } + + if (ShellStatus == SHELL_SUCCESS && Index == NoHandles) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SERMODE_BAD_HANDLE), gShellDebug1HiiHandle, L"sermode", HandleIdx); + ShellStatus = SHELL_INVALID_PARAMETER; + } + +Done: + if (Package != NULL) { + ShellCommandLineFreeVarList (Package); + } + if (Handles != NULL) { + FreePool (Handles); + } + return ShellStatus; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SetSize.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SetSize.c new file mode 100644 index 00000000..09250b09 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SetSize.c @@ -0,0 +1,104 @@ +/** @file + Main file for SetSize shell Debug1 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDebug1CommandsLib.h" + +/** + Function for 'setsize' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunSetSize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CONST CHAR16 *Temp1; + UINTN NewSize; + UINTN LoopVar; + SHELL_FILE_HANDLE FileHandle; + + ShellStatus = SHELL_SUCCESS; + Status = EFI_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"setsize", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetCount(Package) < 3) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"setsize"); + ShellStatus = SHELL_INVALID_PARAMETER; + NewSize = 0; + } else { + Temp1 = ShellCommandLineGetRawValue(Package, 1); + if (!ShellIsHexOrDecimalNumber(Temp1, FALSE, FALSE)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SIZE_NOT_SPEC), gShellDebug1HiiHandle, L"setsize"); + ShellStatus = SHELL_INVALID_PARAMETER; + NewSize = 0; + } else { + NewSize = ShellStrToUintn(Temp1); + } + } + for (LoopVar = 2 ; LoopVar < ShellCommandLineGetCount(Package) && ShellStatus == SHELL_SUCCESS ; LoopVar++) { + Status = ShellOpenFileByName(ShellCommandLineGetRawValue(Package, LoopVar), &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0); + if (EFI_ERROR(Status)) { + Status = ShellOpenFileByName(ShellCommandLineGetRawValue(Package, LoopVar), &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0); + } + if (EFI_ERROR(Status) && LoopVar == 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_FILE_NOT_SPEC), gShellDebug1HiiHandle, L"setsize"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"setsize", ShellCommandLineGetRawValue(Package, LoopVar)); + ShellStatus = SHELL_INVALID_PARAMETER; + break; + } else { + Status = FileHandleSetSize(FileHandle, NewSize); + if (Status == EFI_VOLUME_FULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_VOLUME_FULL), gShellDebug1HiiHandle, L"setsize"); + ShellStatus = SHELL_VOLUME_FULL; + } else if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SET_SIZE_FAIL), gShellDebug1HiiHandle, L"setsize", ShellCommandLineGetRawValue(Package, LoopVar)); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SET_SIZE_DONE), gShellDebug1HiiHandle, ShellCommandLineGetRawValue(Package, LoopVar)); + } + ShellCloseFile(&FileHandle); + } + } + + ShellCommandLineFreeVarList (Package); + } + + return (ShellStatus); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SetVar.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SetVar.c new file mode 100644 index 00000000..0ec6edff --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SetVar.c @@ -0,0 +1,469 @@ +/** @file + Main file for SetVar shell Debug1 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDebug1CommandsLib.h" + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-guid", TypeValue}, + {L"-bs", TypeFlag}, + {L"-rt", TypeFlag}, + {L"-nv", TypeFlag}, + {NULL, TypeMax} + }; + +typedef enum { + DataTypeHexNumber = 0, + DataTypeHexArray = 1, + DataTypeAscii = 2, + DataTypeUnicode = 3, + DataTypeDevicePath = 4, + DataTypeUnKnow = 5 +} DATA_TYPE; + +typedef union { + UINT8 HexNumber8; + UINT16 HexNumber16; + UINT32 HexNumber32; + UINT64 HexNumber64; +} HEX_NUMBER; + +/** + Check if the input is a (potentially empty) string of hexadecimal nibbles. + + @param[in] String The CHAR16 string to check. + + @retval FALSE A character has been found in String for which + ShellIsHexaDecimalDigitCharacter() returned FALSE. + + @retval TRUE Otherwise. (Note that this covers the case when String is + empty.) +**/ +BOOLEAN +IsStringOfHexNibbles ( + IN CONST CHAR16 *String + ) +{ + CONST CHAR16 *Pos; + + for (Pos = String; *Pos != L'\0'; ++Pos) { + if (!ShellIsHexaDecimalDigitCharacter (*Pos)) { + return FALSE; + } + } + return TRUE; +} + +/** + Function to check the TYPE of Data. + + @param[in] Data The Data to be check. + + @retval DATA_TYPE The TYPE of Data. +**/ +DATA_TYPE +TestDataType ( + IN CONST CHAR16 *Data + ) +{ + if (Data[0] == L'0' && (Data[1] == L'x' || Data[1] == L'X')) { + if (IsStringOfHexNibbles (Data+2) && StrLen (Data + 2) <= 16) { + return DataTypeHexNumber; + } else { + return DataTypeUnKnow; + } + } else if (Data[0] == L'H') { + if (IsStringOfHexNibbles (Data + 1) && StrLen (Data + 1) % 2 == 0) { + return DataTypeHexArray; + } else { + return DataTypeUnKnow; + } + } else if (Data[0] == L'S') { + return DataTypeAscii; + } else if (Data[0] == L'L') { + return DataTypeUnicode; + } else if (Data[0] == L'P' || StrnCmp (Data, L"--", 2) == 0) { + return DataTypeDevicePath; + } + + if (IsStringOfHexNibbles (Data) && StrLen (Data) % 2 == 0) { + return DataTypeHexArray; + } + + return DataTypeAscii; +} + +/** + Function to parse the Data by the type of Data, and save in the Buffer. + + @param[in] Data A pointer to a buffer to be parsed. + @param[out] Buffer A pointer to a buffer to hold the return data. + @param[in,out] BufferSize On input, indicates the size of Buffer in bytes. + On output,indicates the size of data return in Buffer. + Or the size in bytes of the buffer needed to obtain. + + @retval EFI_INVALID_PARAMETER The Buffer or BufferSize is NULL. + @retval EFI_BUFFER_TOO_SMALL The Buffer is too small to hold the data. + @retval EFI_OUT_OF_RESOURCES A memory allcation failed. + @retval EFI_SUCCESS The Data parsed successful and save in the Buffer. +**/ +EFI_STATUS +ParseParameterData ( + IN CONST CHAR16 *Data, + OUT VOID *Buffer, + IN OUT UINTN *BufferSize + ) +{ + UINT64 HexNumber; + UINTN HexNumberLen; + UINTN Size; + CHAR8 *AsciiBuffer; + DATA_TYPE DataType; + EFI_DEVICE_PATH_PROTOCOL *DevPath; + EFI_STATUS Status; + + HexNumber = 0; + HexNumberLen = 0; + Size = 0; + AsciiBuffer = NULL; + DevPath = NULL; + Status = EFI_SUCCESS; + + if (Data == NULL || BufferSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + DataType = TestDataType (Data); + if (DataType == DataTypeHexNumber) { + // + // hex number + // + StrHexToUint64S (Data + 2, NULL, &HexNumber); + HexNumberLen = StrLen (Data + 2); + if (HexNumberLen >= 1 && HexNumberLen <= 2) { + Size = 1; + } else if (HexNumberLen >= 3 && HexNumberLen <= 4) { + Size = 2; + } else if (HexNumberLen >= 5 && HexNumberLen <= 8) { + Size = 4; + } else if (HexNumberLen >= 9 && HexNumberLen <= 16) { + Size = 8; + } + if (Buffer != NULL && *BufferSize >= Size) { + CopyMem(Buffer, (VOID *)&HexNumber, Size); + } else { + Status = EFI_BUFFER_TOO_SMALL; + } + *BufferSize = Size; + } else if (DataType == DataTypeHexArray) { + // + // hex array + // + if (*Data == L'H') { + Data = Data + 1; + } + + Size = StrLen (Data) / 2; + if (Buffer != NULL && *BufferSize >= Size) { + StrHexToBytes(Data, StrLen (Data), (UINT8 *)Buffer, Size); + } else { + Status = EFI_BUFFER_TOO_SMALL; + } + *BufferSize = Size; + } else if (DataType == DataTypeAscii) { + // + // ascii text + // + if (*Data == L'S') { + Data = Data + 1; + } + AsciiBuffer = AllocateZeroPool (StrSize (Data) / 2); + if (AsciiBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + AsciiSPrint (AsciiBuffer, StrSize (Data) / 2, "%s", (CHAR8 *)Data); + + Size = StrSize (Data) / 2 - 1; + if (Buffer != NULL && *BufferSize >= Size) { + CopyMem (Buffer, AsciiBuffer, Size); + } else { + Status = EFI_BUFFER_TOO_SMALL; + } + *BufferSize = Size; + } + SHELL_FREE_NON_NULL (AsciiBuffer); + } else if (DataType == DataTypeUnicode) { + // + // unicode text + // + if (*Data == L'L') { + Data = Data + 1; + } + Size = StrSize (Data) - sizeof (CHAR16); + if (Buffer != NULL && *BufferSize >= Size) { + CopyMem (Buffer, Data, Size); + } else { + Status = EFI_BUFFER_TOO_SMALL; + } + *BufferSize = Size; + } else if (DataType == DataTypeDevicePath) { + if (*Data == L'P') { + Data = Data + 1; + } else if (StrnCmp (Data, L"--", 2) == 0) { + Data = Data + 2; + } + DevPath = ConvertTextToDevicePath (Data); + if (DevPath == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SETVAR_ERROR_DPFT), gShellDebug1HiiHandle, L"setvar"); + Status = EFI_INVALID_PARAMETER; + } else { + Size = GetDevicePathSize (DevPath); + if (Buffer != NULL && *BufferSize >= Size) { + CopyMem (Buffer, DevPath, Size); + } else { + Status = EFI_BUFFER_TOO_SMALL; + } + *BufferSize = Size; + } + SHELL_FREE_NON_NULL (DevPath); + } else { + Status = EFI_INVALID_PARAMETER; + } + + return Status; +} + +/** + Function to get each data from parameters. + + @param[in] Package The package of checked values. + @param[out] Buffer A pointer to a buffer to hold the return data. + @param[out] BufferSize Indicates the size of data in bytes return in Buffer. + + @retval EFI_INVALID_PARAMETER Buffer or BufferSize is NULL. + @retval EFI_OUT_OF_RESOURCES A memory allcation failed. + @retval EFI_SUCCESS Get each parameter data was successful. +**/ +EFI_STATUS +GetVariableDataFromParameter ( + IN CONST LIST_ENTRY *Package, + OUT UINT8 **Buffer, + OUT UINTN *BufferSize + ) +{ + CONST CHAR16 *TempData; + UINTN Index; + UINTN TotalSize; + UINTN Size; + UINT8 *BufferWalker; + EFI_STATUS Status; + + TotalSize = 0; + Size = 0; + Status = EFI_SUCCESS; + + if (BufferSize == NULL || Buffer == NULL || ShellCommandLineGetCount (Package) < 3) { + return EFI_INVALID_PARAMETER; + } + + for (Index = 2; Index < ShellCommandLineGetCount (Package); Index++) { + TempData = ShellCommandLineGetRawValue (Package, Index); + ASSERT (TempData != NULL); + + if (TempData[0] != L'=') { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"setvar", TempData); + return EFI_INVALID_PARAMETER; + } + + TempData = TempData + 1; + Size = 0; + Status = ParseParameterData (TempData, NULL, &Size); + if (EFI_ERROR (Status)) { + if (Status == EFI_BUFFER_TOO_SMALL) { + // + // We expect return EFI_BUFFER_TOO_SMALL when pass 'NULL' as second parameter to the function ParseParameterData. + // + TotalSize += Size; + } else { + if (Status == EFI_INVALID_PARAMETER) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"setvar", TempData); + } else if (Status == EFI_NOT_FOUND) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SETVAR_ERROR_DPFT), gShellDebug1HiiHandle, L"setvar"); + } + return Status; + } + } + } + + *BufferSize = TotalSize; + *Buffer = AllocateZeroPool (TotalSize); + + if (*Buffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + BufferWalker = *Buffer; + for (Index = 2; Index < ShellCommandLineGetCount (Package); Index++) { + TempData = ShellCommandLineGetRawValue (Package, Index); + TempData = TempData + 1; + + Size = TotalSize; + Status = ParseParameterData (TempData, (VOID *)BufferWalker, &Size); + if (!EFI_ERROR (Status)) { + BufferWalker = BufferWalker + Size; + TotalSize = TotalSize - Size; + } else { + return Status; + } + } + } + + return EFI_SUCCESS; +} + +/** + Function for 'setvar' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunSetVar ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + RETURN_STATUS RStatus; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CONST CHAR16 *VariableName; + EFI_GUID Guid; + CONST CHAR16 *StringGuid; + UINT32 Attributes; + VOID *Buffer; + UINTN Size; + UINTN LoopVar; + + ShellStatus = SHELL_SUCCESS; + Status = EFI_SUCCESS; + Buffer = NULL; + Size = 0; + Attributes = 0; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"setvar", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else if (ShellCommandLineCheckDuplicate (Package,&ProblemParam) != EFI_SUCCESS) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DUPLICATE), gShellDebug1HiiHandle, L"setvar", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + if (ShellCommandLineGetCount(Package) < 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"setvar"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + VariableName = ShellCommandLineGetRawValue(Package, 1); + if (!ShellCommandLineGetFlag(Package, L"-guid")){ + CopyGuid(&Guid, &gEfiGlobalVariableGuid); + } else { + StringGuid = ShellCommandLineGetValue(Package, L"-guid"); + RStatus = StrToGuid (StringGuid, &Guid); + if (RETURN_ERROR (RStatus) || (StringGuid[GUID_STRING_LENGTH] != L'\0')) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"setvar", StringGuid); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } + + if (ShellCommandLineGetCount(Package) == 2) { + // + // Display + // + Status = gRT->GetVariable((CHAR16*)VariableName, &Guid, &Attributes, &Size, Buffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + Buffer = AllocateZeroPool(Size); + Status = gRT->GetVariable((CHAR16*)VariableName, &Guid, &Attributes, &Size, Buffer); + } + if (!EFI_ERROR(Status) && Buffer != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_SETVAR_PRINT), gShellDebug1HiiHandle, &Guid, VariableName, Size); + for (LoopVar = 0; LoopVar < Size; LoopVar++) { + ShellPrintEx(-1, -1, L"%02x ", ((UINT8*)Buffer)[LoopVar]); + } + ShellPrintEx(-1, -1, L"\r\n"); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SETVAR_ERROR_GET), gShellDebug1HiiHandle, L"setvar", &Guid, VariableName); + ShellStatus = SHELL_ACCESS_DENIED; + } + } else { + // + // Create, Delete or Modify. + // + Status = gRT->GetVariable((CHAR16*)VariableName, &Guid, &Attributes, &Size, Buffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + Buffer = AllocateZeroPool(Size); + Status = gRT->GetVariable((CHAR16*)VariableName, &Guid, &Attributes, &Size, Buffer); + } + if (EFI_ERROR(Status) || Buffer == NULL) { + // + // Creating a new variable. determine attributes from command line. + // + Attributes = 0; + if (ShellCommandLineGetFlag(Package, L"-bs")) { + Attributes |= EFI_VARIABLE_BOOTSERVICE_ACCESS; + } + if (ShellCommandLineGetFlag(Package, L"-rt")) { + Attributes |= EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_BOOTSERVICE_ACCESS; + } + if (ShellCommandLineGetFlag(Package, L"-nv")) { + Attributes |= EFI_VARIABLE_NON_VOLATILE; + } + } + SHELL_FREE_NON_NULL(Buffer); + + Size = 0; + Status = GetVariableDataFromParameter(Package, (UINT8 **)&Buffer, &Size); + if (!EFI_ERROR(Status)) { + Status = gRT->SetVariable((CHAR16*)VariableName, &Guid, Attributes, Size, Buffer); + } + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_SETVAR_ERROR_SET), gShellDebug1HiiHandle, L"setvar", &Guid, VariableName); + ShellStatus = SHELL_ACCESS_DENIED; + } else { + ASSERT(ShellStatus == SHELL_SUCCESS); + } + } + } + ShellCommandLineFreeVarList (Package); + } + + if (Buffer != NULL) { + FreePool(Buffer); + } + + return (ShellStatus); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/EventLogInfo.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/EventLogInfo.c new file mode 100644 index 00000000..48b6b2c1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/EventLogInfo.c @@ -0,0 +1,409 @@ +/** @file + Module for clarifying the content of the smbios structure element info. + + Copyright (c) 2005 - 2019, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDebug1CommandsLib.h" +#include "PrintInfo.h" +#include "QueryTable.h" +#include "EventLogInfo.h" + +/** + Function to display system event log access information. + + @param[in] Key Additional information to print. + @param[in] Option Whether to print the additional information. +**/ +VOID +DisplaySELAccessMethod ( + IN CONST UINT8 Key, + IN CONST UINT8 Option + ) +{ + // + // Print prompt + // + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_ACCESS_METHOD), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Key, Option); + + // + // Print value info + // + switch (Key) { + case 0: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_ONE_EIGHT_BIT), gShellDebug1HiiHandle); + break; + + case 1: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_TWO_EIGHT_BITS), gShellDebug1HiiHandle); + break; + + case 2: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_ONE_SIXTEEN_BIT), gShellDebug1HiiHandle); + break; + + case 3: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_MEM_MAPPED_PHYS), gShellDebug1HiiHandle); + break; + + case 4: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_AVAIL_VIA_GENERAL), gShellDebug1HiiHandle); + break; + + default: + if (Key <= 0x7f) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_AVAIL_FOR_FUTURE_ASSIGN), gShellDebug1HiiHandle); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_BIOS_VENDOR_OEM), gShellDebug1HiiHandle); + } + } +} + +/** + Function to display system event log status information. + + @param[in] Key Additional information to print. + @param[in] Option Whether to print the additional information. +**/ +VOID +DisplaySELLogStatus ( + UINT8 Key, + UINT8 Option + ) +{ + // + // Print prompt + // + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_LOG_STATUS), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Key, Option); + + // + // Print value info + // + if ((Key & 0x01) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_LOG_AREA_VALID), gShellDebug1HiiHandle); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_LOG_AREA_VALID), gShellDebug1HiiHandle); + } + + if ((Key & 0x02) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_LOG_AREA_FULL), gShellDebug1HiiHandle); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_LOG_AREA_NOT_FULL), gShellDebug1HiiHandle); + } + + if ((Key & 0xFC) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_RES_BITS_NOT_ZERO), gShellDebug1HiiHandle, Key & 0xFC); + } +} + +/** + Function to display system event log header format information. + + @param[in] Key Additional information to print. + @param[in] Option Whether to print the additional information. +**/ +VOID +DisplaySysEventLogHeaderFormat ( + UINT8 Key, + UINT8 Option + ) +{ + // + // Print prompt + // + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_LOG_HEADER_FORMAT), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Key, Option); + + // + // Print value info + // + if (Key == 0x00) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_NO_HEADER), gShellDebug1HiiHandle); + } else if (Key == 0x01) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_TYPE_LOG_HEADER), gShellDebug1HiiHandle); + } else if (Key <= 0x7f) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_AVAIL_FOR_FUTURE), gShellDebug1HiiHandle); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_BIOS_VENDOR), gShellDebug1HiiHandle); + } +} + +/** + Display the header information for SEL log items. + + @param[in] Key The information key. + @param[in] Option The option index. +**/ +VOID +DisplaySELLogHeaderLen ( + UINT8 Key, + UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_LOG_HEADER_LEN), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Key, Option); + + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_ONE_VAR_D), gShellDebug1HiiHandle, Key & 0x7F); + + // + // The most-significant bit of the field specifies + // whether (0) or not (1) the record has been read + // + if ((Key & 0x80) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_THIS_RECORD_READ), gShellDebug1HiiHandle); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_THIS_RECORD_NOT_READ), gShellDebug1HiiHandle); + } +} + +/** + Display the header information for type 1 items. + + @param[in] LogHeader The buffer with the information. +**/ +VOID +DisplaySysEventLogHeaderType1 ( + IN UINT8 *LogHeader + ) +{ + LOG_HEADER_TYPE1_FORMAT *Header; + + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_SYSTEM_EVENT_LOG), gShellDebug1HiiHandle); + + // + // Print Log Header Type1 Format info + // + Header = (LOG_HEADER_TYPE1_FORMAT *) (LogHeader); + + ShellPrintHiiEx(-1,-1,NULL, + STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_OEM_RESERVED), + gShellDebug1HiiHandle, + Header->OEMReserved[0], + Header->OEMReserved[1], + Header->OEMReserved[2], + Header->OEMReserved[3], + Header->OEMReserved[4] + ); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_MULTIPLE_EVENT_TIME), gShellDebug1HiiHandle, Header->Metw); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_MULTIPLE_EVENT_COUNT), gShellDebug1HiiHandle, Header->Meci); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_PREBOOT_ADDRESS), gShellDebug1HiiHandle, Header->CMOSAddress); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_PREBOOT_INDEX), gShellDebug1HiiHandle, Header->CMOSBitIndex); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_CHECKSUM_STARTING_OFF), gShellDebug1HiiHandle, Header->StartingOffset); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_CHECKSUN_BYTE_COUNT), gShellDebug1HiiHandle, Header->ChecksumOffset); + ShellPrintHiiEx(-1,-1,NULL, + STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_RESERVED), + gShellDebug1HiiHandle, + Header->OEMReserved[0], + Header->OEMReserved[1], + Header->OEMReserved[2] + ); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_HEADER_REVISION), gShellDebug1HiiHandle, Header->HeaderRevision); +} + +/** + Function to display system event log header information. + + @param[in] LogHeaderFormat Format identifier. + @param[in] LogHeader Format informcation. +**/ +VOID +DisplaySysEventLogHeader ( + UINT8 LogHeaderFormat, + UINT8 *LogHeader + ) +{ + // + // Print prompt + // + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_LOG_HEADER), gShellDebug1HiiHandle); + + // + // Print value info + // + if (LogHeaderFormat == 0x00) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_NO_HEADER), gShellDebug1HiiHandle); + } else if (LogHeaderFormat == 0x01) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_TYPE_LOG_HEADER), gShellDebug1HiiHandle); + DisplaySysEventLogHeaderType1 (LogHeader); + } else if (LogHeaderFormat <= 0x7f) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_AVAIL_FUTURE_ASSIGN), gShellDebug1HiiHandle); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_BIOS_VENDOR), gShellDebug1HiiHandle); + } +} + +/** + Display the El Vdf information. + + @param[in] ElVdfType The information type. + @param[in] VarData The information buffer. +**/ +VOID +DisplayElVdfInfo ( + UINT8 ElVdfType, + UINT8 *VarData + ) +{ + UINT16 *Word; + UINT32 *Dword; + + // + // Display Type Name + // + DisplaySELVarDataFormatType (ElVdfType, SHOW_DETAIL); + + // + // Display Type description + // + switch (ElVdfType) { + case 0: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_NO_STD_FORMAT), gShellDebug1HiiHandle); + break; + + case 1: + Word = (UINT16 *) (VarData + 1); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_SMBIOS_STRUCT_ASSOC), gShellDebug1HiiHandle); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_STRUCT_HANDLE), gShellDebug1HiiHandle, *Word); + break; + + case 2: + Dword = (UINT32 *) (VarData + 1); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_MULT_EVENT_COUNTER), gShellDebug1HiiHandle, *Dword); + break; + + case 3: + Word = (UINT16 *) (VarData + 1); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_SMBIOS_STRUCT_ASSOC), gShellDebug1HiiHandle); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_STRUCT_HANDLE), gShellDebug1HiiHandle, *Word); + // + // Followed by a multiple-event counter + // + Dword = (UINT32 *) (VarData + 1); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_MULT_EVENT_COUNTER), gShellDebug1HiiHandle, *Dword); + break; + + case 4: + Dword = (UINT32 *) (VarData + 1); + DisplayPostResultsBitmapDw1 (*Dword, SHOW_DETAIL); + Dword++; + DisplayPostResultsBitmapDw2 (*Dword, SHOW_DETAIL); + break; + + case 5: + Dword = (UINT32 *) (VarData + 1); + DisplaySELSysManagementTypes (*Dword, SHOW_DETAIL); + break; + + case 6: + Dword = (UINT32 *) (VarData + 1); + DisplaySELSysManagementTypes (*Dword, SHOW_DETAIL); + // + // Followed by a multiple-event counter + // + Dword = (UINT32 *) (VarData + 1); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_MULT_EVENT_COUNTER), gShellDebug1HiiHandle, *Dword); + break; + + default: + if (ElVdfType <= 0x7F) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_UNUSED_AVAIL_FOR_ASSIGN), gShellDebug1HiiHandle); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_AVAIL_FOR_SYSTEM), gShellDebug1HiiHandle); + } + } +} + +/** + Function to display system event log data. + + @param[in] LogData The data information. + @param[in] LogAreaLength Length of the data. +**/ +VOID +DisplaySysEventLogData ( + UINT8 *LogData, + UINT16 LogAreaLength + ) +{ + LOG_RECORD_FORMAT *Log; + UINT8 ElVdfType; + // + // Event Log Variable Data Format Types + // + UINTN Offset; + + // + // Print prompt + // + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_SYSTEM_EVENT_LOG_2), gShellDebug1HiiHandle); + + // + // Print Log info + // + Offset = 0; + Log = (LOG_RECORD_FORMAT *) LogData; + while (Log != NULL && Log->Type != END_OF_LOG && Offset < LogAreaLength) { + + if (Log != NULL) { + // + // Display Event Log Record Information + // + DisplaySELTypes (Log->Type, SHOW_DETAIL); + DisplaySELLogHeaderLen (Log->Length, SHOW_DETAIL); + + Offset += Log->Length; + // + // Display Log Header Date/Time Fields + // These fields contain the BCD representation of the date and time + // (as read from CMOS) of the occurrence of the event + // So Print as hex and represent decimal + // + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_DATE), gShellDebug1HiiHandle); + if (Log != NULL && Log->Year >= 80 && Log->Year <= 99) { + Print (L"19"); + } else if (Log != NULL && Log->Year <= 79) { + Print (L"20"); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_ERROR), gShellDebug1HiiHandle); + // + // Get a Event Log Record + // + Log = (LOG_RECORD_FORMAT *) (LogData + Offset); + continue; + } + + ShellPrintHiiEx(-1,-1,NULL, + STRING_TOKEN (STR_SMBIOSVIEW_EVENTLOGINFO_TIME_SIX_VARS), + gShellDebug1HiiHandle, + Log->Year, + Log->Month, + Log->Day, + Log->Hour, + Log->Minute, + Log->Second + ); + + // + // Display Variable Data Format + // + if (Log->Length <= (sizeof (LOG_RECORD_FORMAT) - 1)) { + // + // Get a Event Log Record + // + Log = (LOG_RECORD_FORMAT *) (LogData + Offset); + continue; + } + + ElVdfType = Log->LogVariableData[0]; + DisplayElVdfInfo (ElVdfType, Log->LogVariableData); + // + // Get a Event Log Record + // + Log = (LOG_RECORD_FORMAT *) (LogData + Offset); + } + } +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/EventLogInfo.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/EventLogInfo.h new file mode 100644 index 00000000..bfc2c189 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/EventLogInfo.h @@ -0,0 +1,106 @@ +/** @file + Module to clarify system event log of smbios structure. + + Copyright (c) 2005-2011, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SMBIOS_EVENT_LOG_INFO_H_ +#define _SMBIOS_EVENT_LOG_INFO_H_ + +#define END_OF_LOG 0xFF + +#pragma pack(1) + +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Year; + UINT8 Month; + UINT8 Day; + UINT8 Hour; + UINT8 Minute; + UINT8 Second; + UINT8 LogVariableData[1]; +} LOG_RECORD_FORMAT; + +typedef struct { + UINT8 OEMReserved[5]; + UINT8 Metw; // Multiple Event Time Window + UINT8 Meci; // Multiple Event Count Increment + UINT8 CMOSAddress; // Pre-boot Event Log Reset - CMOS Address + UINT8 CMOSBitIndex; // Pre-boot Event Log Reset - CMOS Bit Index + UINT8 StartingOffset; // CMOS Checksum - Starting Offset + UINT8 ByteCount; // CMOS Checksum - Byte Count + UINT8 ChecksumOffset; // CMOS Checksum - Checksum Offset + UINT8 Reserved[3]; + UINT8 HeaderRevision; +} LOG_HEADER_TYPE1_FORMAT; + +#pragma pack() +// +// System Event Log (Type 15) +// + +/** + Function to display system event log access information. + + @param[in] Key Additional information to print. + @param[in] Option Whether to print the additional information. +**/ +VOID +DisplaySELAccessMethod ( + IN CONST UINT8 Key, + IN CONST UINT8 Option + ); + +/** + Function to display system event log status information. + + @param[in] Key Additional information to print. + @param[in] Option Whether to print the additional information. +**/ +VOID +DisplaySELLogStatus ( + UINT8 Key, + UINT8 Option + ); + +/** + Function to display system event log header format information. + + @param[in] Key Additional information to print. + @param[in] Option Whether to print the additional information. +**/ +VOID +DisplaySysEventLogHeaderFormat ( + UINT8 Key, + UINT8 Option + ); + +/** + Function to display system event log header information. + + @param[in] LogHeaderFormat Format identifier. + @param[in] LogHeader Format informcation. +**/ +VOID +DisplaySysEventLogHeader ( + UINT8 LogHeaderFormat, + UINT8 *LogHeader + ); + +/** + Function to display system event log data. + + @param[in] LogData The data information. + @param[in] LogAreaLength Length of the data. +**/ +VOID +DisplaySysEventLogData ( + UINT8 *LogData, + UINT16 LogAreaLength + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/LibSmbiosView.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/LibSmbiosView.c new file mode 100644 index 00000000..f86e6113 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/LibSmbiosView.c @@ -0,0 +1,367 @@ +/** @file + API for SMBIOS table. + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "UefiShellDebug1CommandsLib.h" +#include +#include "LibSmbiosView.h" +#include "SmbiosView.h" + +STATIC UINT8 mInit = 0; +STATIC UINT8 m64Init = 0; +STATIC SMBIOS_TABLE_ENTRY_POINT *mSmbiosTable = NULL; +STATIC SMBIOS_TABLE_3_0_ENTRY_POINT *mSmbios64BitTable = NULL; +STATIC SMBIOS_STRUCTURE_POINTER m_SmbiosStruct; +STATIC SMBIOS_STRUCTURE_POINTER *mSmbiosStruct = &m_SmbiosStruct; +STATIC SMBIOS_STRUCTURE_POINTER m_Smbios64BitStruct; +STATIC SMBIOS_STRUCTURE_POINTER *mSmbios64BitStruct = &m_Smbios64BitStruct; + +/** + Init the SMBIOS VIEW API's environment. + + @retval EFI_SUCCESS Successful to init the SMBIOS VIEW Lib. +**/ +EFI_STATUS +LibSmbiosInit ( + VOID + ) +{ + EFI_STATUS Status; + + // + // Init only once + // + if (mInit == 1) { + return EFI_SUCCESS; + } + // + // Get SMBIOS table from System Configure table + // + Status = GetSystemConfigurationTable (&gEfiSmbiosTableGuid, (VOID**)&mSmbiosTable); + + if (mSmbiosTable == NULL) { + return EFI_NOT_FOUND; + } + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_LIBSMBIOSVIEW_GET_TABLE_ERROR), gShellDebug1HiiHandle, Status); + return Status; + } + // + // Init SMBIOS structure table address + // + mSmbiosStruct->Raw = (UINT8 *) (UINTN) (mSmbiosTable->TableAddress); + + mInit = 1; + return EFI_SUCCESS; +} + +/** + Init the SMBIOS VIEW API's environment. + + @retval EFI_SUCCESS Successful to init the SMBIOS VIEW Lib. +**/ +EFI_STATUS +LibSmbios64BitInit ( + VOID + ) +{ + EFI_STATUS Status; + + // + // Init only once + // + if (m64Init == 1) { + return EFI_SUCCESS; + } + // + // Get SMBIOS table from System Configure table + // + Status = GetSystemConfigurationTable (&gEfiSmbios3TableGuid, (VOID**)&mSmbios64BitTable); + + if (mSmbios64BitTable == NULL) { + return EFI_NOT_FOUND; + } + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_LIBSMBIOSVIEW_GET_TABLE_ERROR), gShellDebug1HiiHandle, Status); + return Status; + } + // + // Init SMBIOS structure table address + // + mSmbios64BitStruct->Raw = (UINT8 *) (UINTN) (mSmbios64BitTable->TableAddress); + + m64Init = 1; + return EFI_SUCCESS; +} + +/** + Cleanup the Smbios information. +**/ +VOID +LibSmbiosCleanup ( + VOID + ) +{ + // + // Release resources + // + if (mSmbiosTable != NULL) { + mSmbiosTable = NULL; + } + + mInit = 0; +} + +/** + Cleanup the Smbios information. +**/ +VOID +LibSmbios64BitCleanup ( + VOID + ) +{ + // + // Release resources + // + if (mSmbios64BitTable != NULL) { + mSmbios64BitTable = NULL; + } + + m64Init = 0; +} + +/** + Get the entry point structure for the table. + + @param[out] EntryPointStructure The pointer to populate. +**/ +VOID +LibSmbiosGetEPS ( + OUT SMBIOS_TABLE_ENTRY_POINT **EntryPointStructure + ) +{ + // + // return SMBIOS Table address + // + *EntryPointStructure = mSmbiosTable; +} + +/** + Get the entry point structure for the table. + + @param[out] EntryPointStructure The pointer to populate. +**/ +VOID +LibSmbios64BitGetEPS ( + OUT SMBIOS_TABLE_3_0_ENTRY_POINT **EntryPointStructure + ) +{ + // + // return SMBIOS Table address + // + *EntryPointStructure = mSmbios64BitTable; +} + +/** + Return SMBIOS string for the given string number. + + @param[in] Smbios Pointer to SMBIOS structure. + @param[in] StringNumber String number to return. -1 is used to skip all strings and + point to the next SMBIOS structure. + + @return Pointer to string, or pointer to next SMBIOS strcuture if StringNumber == -1 +**/ +CHAR8* +LibGetSmbiosString ( + IN SMBIOS_STRUCTURE_POINTER *Smbios, + IN UINT16 StringNumber + ) +{ + UINT16 Index; + CHAR8 *String; + + ASSERT (Smbios != NULL); + + // + // Skip over formatted section + // + String = (CHAR8 *) (Smbios->Raw + Smbios->Hdr->Length); + + // + // Look through unformated section + // + for (Index = 1; Index <= StringNumber; Index++) { + if (StringNumber == Index) { + return String; + } + // + // Skip string + // + for (; *String != 0; String++); + String++; + + if (*String == 0) { + // + // If double NULL then we are done. + // Return pointer to next structure in Smbios. + // if you pass in a -1 you will always get here + // + Smbios->Raw = (UINT8 *)++String; + return NULL; + } + } + + return NULL; +} + +/** + Get SMBIOS structure for the given Handle, + Handle is changed to the next handle or 0xFFFF when the end is + reached or the handle is not found. + + @param[in, out] Handle 0xFFFF: get the first structure + Others: get a structure according to this value. + @param[out] Buffer The pointer to the pointer to the structure. + @param[out] Length Length of the structure. + + @retval DMI_SUCCESS Handle is updated with next structure handle or + 0xFFFF(end-of-list). + + @retval DMI_INVALID_HANDLE Handle is updated with first structure handle or + 0xFFFF(end-of-list). +**/ +EFI_STATUS +LibGetSmbiosStructure ( + IN OUT UINT16 *Handle, + OUT UINT8 **Buffer, + OUT UINT16 *Length + ) +{ + SMBIOS_STRUCTURE_POINTER Smbios; + SMBIOS_STRUCTURE_POINTER SmbiosEnd; + UINT8 *Raw; + + if (*Handle == INVALID_HANDLE) { + *Handle = mSmbiosStruct->Hdr->Handle; + return DMI_INVALID_HANDLE; + } + + if ((Buffer == NULL) || (Length == NULL)) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_LIBSMBIOSVIEW_NO_BUFF_LEN_SPEC), gShellDebug1HiiHandle); + return DMI_INVALID_HANDLE; + } + + *Length = 0; + Smbios.Hdr = mSmbiosStruct->Hdr; + SmbiosEnd.Raw = Smbios.Raw + mSmbiosTable->TableLength; + while (Smbios.Raw < SmbiosEnd.Raw) { + if (Smbios.Hdr->Handle == *Handle) { + Raw = Smbios.Raw; + // + // Walk to next structure + // + LibGetSmbiosString (&Smbios, (UINT16) (-1)); + // + // Length = Next structure head - this structure head + // + *Length = (UINT16) (Smbios.Raw - Raw); + *Buffer = Raw; + // + // update with the next structure handle. + // + if (Smbios.Raw < SmbiosEnd.Raw) { + *Handle = Smbios.Hdr->Handle; + } else { + *Handle = INVALID_HANDLE; + } + return DMI_SUCCESS; + } + // + // Walk to next structure + // + LibGetSmbiosString (&Smbios, (UINT16) (-1)); + } + + *Handle = INVALID_HANDLE; + return DMI_INVALID_HANDLE; +} + +/** + Get SMBIOS structure for the given Handle, + Handle is changed to the next handle or 0xFFFF when the end is + reached or the handle is not found. + + @param[in, out] Handle 0xFFFF: get the first structure + Others: get a structure according to this value. + @param[out] Buffer The pointer to the pointer to the structure. + @param[out] Length Length of the structure. + + @retval DMI_SUCCESS Handle is updated with next structure handle or + 0xFFFF(end-of-list). + + @retval DMI_INVALID_HANDLE Handle is updated with first structure handle or + 0xFFFF(end-of-list). +**/ +EFI_STATUS +LibGetSmbios64BitStructure ( + IN OUT UINT16 *Handle, + OUT UINT8 **Buffer, + OUT UINT16 *Length + ) +{ + SMBIOS_STRUCTURE_POINTER Smbios; + SMBIOS_STRUCTURE_POINTER SmbiosEnd; + UINT8 *Raw; + + if (*Handle == INVALID_HANDLE) { + *Handle = mSmbios64BitStruct->Hdr->Handle; + return DMI_INVALID_HANDLE; + } + + if ((Buffer == NULL) || (Length == NULL)) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_LIBSMBIOSVIEW_NO_BUFF_LEN_SPEC), gShellDebug1HiiHandle); + return DMI_INVALID_HANDLE; + } + + *Length = 0; + Smbios.Hdr = mSmbios64BitStruct->Hdr; + + SmbiosEnd.Raw = Smbios.Raw + mSmbios64BitTableLength; + while (Smbios.Raw < SmbiosEnd.Raw) { + if (Smbios.Hdr->Handle == *Handle) { + Raw = Smbios.Raw; + // + // Walk to next structure + // + LibGetSmbiosString (&Smbios, (UINT16) (-1)); + // + // Length = Next structure head - this structure head + // + *Length = (UINT16) (Smbios.Raw - Raw); + *Buffer = Raw; + // + // update with the next structure handle. + // + if (Smbios.Raw < SmbiosEnd.Raw) { + *Handle = Smbios.Hdr->Handle; + } else { + *Handle = INVALID_HANDLE; + } + return DMI_SUCCESS; + } + // + // Walk to next structure + // + LibGetSmbiosString (&Smbios, (UINT16) (-1)); + } + + *Handle = INVALID_HANDLE; + return DMI_INVALID_HANDLE; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/LibSmbiosView.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/LibSmbiosView.h new file mode 100644 index 00000000..d7f43c9d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/LibSmbiosView.h @@ -0,0 +1,153 @@ +/** @file + API for SMBIOS Plug and Play functions, access to SMBIOS table and structures. + + Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _LIB_SMBIOS_VIEW_H_ +#define _LIB_SMBIOS_VIEW_H_ + +#include + +#define DMI_SUCCESS 0x00 +#define DMI_UNKNOWN_FUNCTION 0x81 +#define DMI_FUNCTION_NOT_SUPPORTED 0x82 +#define DMI_INVALID_HANDLE 0x83 +#define DMI_BAD_PARAMETER 0x84 +#define DMI_INVALID_SUBFUNCTION 0x85 +#define DMI_NO_CHANGE 0x86 +#define DMI_ADD_STRUCTURE_FAILED 0x87 +#define DMI_READ_ONLY 0x8D +#define DMI_LOCK_NOT_SUPPORTED 0x90 +#define DMI_CURRENTLY_LOCKED 0x91 +#define DMI_INVALID_LOCK 0x92 + +#define INVALID_HANDLE (UINT16) (-1) + +#define EFI_SMBIOSERR(val) EFIERR (0x30000 | val) + +#define EFI_SMBIOSERR_FAILURE EFI_SMBIOSERR (1) +#define EFI_SMBIOSERR_STRUCT_NOT_FOUND EFI_SMBIOSERR (2) +#define EFI_SMBIOSERR_TYPE_UNKNOWN EFI_SMBIOSERR (3) +#define EFI_SMBIOSERR_UNSUPPORTED EFI_SMBIOSERR (4) + +/** + Init the SMBIOS VIEW API's environment for the 32-bit table.. + + @retval EFI_SUCCESS Successful to init the SMBIOS VIEW Lib. +**/ +EFI_STATUS +LibSmbiosInit ( + VOID + ); + +/** + Init the SMBIOS VIEW API's environment for the 64-bit table.. + + @retval EFI_SUCCESS Successful to init the SMBIOS VIEW Lib. +**/ +EFI_STATUS +LibSmbios64BitInit ( + VOID + ); + +/** + Cleanup the Smbios information. +**/ +VOID +LibSmbiosCleanup ( + VOID + ); + +/** + Cleanup the Smbios information. +**/ +VOID +LibSmbios64BitCleanup ( + VOID + ); + +/** + Get the entry point structure for the table. + + @param[out] EntryPointStructure The pointer to populate. +**/ +VOID +LibSmbiosGetEPS ( + OUT SMBIOS_TABLE_ENTRY_POINT **EntryPointStructure + ); + +/** + Get the entry point structure for the 64-bit table. + + @param[out] EntryPointStructure The pointer to populate. +**/ +VOID +LibSmbios64BitGetEPS ( + OUT SMBIOS_TABLE_3_0_ENTRY_POINT **EntryPointStructure + ); + +/** + Return SMBIOS string for the given string number. + + @param[in] Smbios Pointer to SMBIOS structure. + @param[in] StringNumber String number to return. -1 is used to skip all strings and + point to the next SMBIOS structure. + + @return Pointer to string, or pointer to next SMBIOS strcuture if StringNumber == -1 +**/ +CHAR8* +LibGetSmbiosString ( + IN SMBIOS_STRUCTURE_POINTER *Smbios, + IN UINT16 StringNumber + ); + +/** + Get SMBIOS structure for the given Handle, + Handle is changed to the next handle or 0xFFFF when the end is + reached or the handle is not found. + + @param[in, out] Handle 0xFFFF: get the first structure + Others: get a structure according to this value. + @param[out] Buffer The pointer to the pointer to the structure. + @param[out] Length Length of the structure. + + @retval DMI_SUCCESS Handle is updated with next structure handle or + 0xFFFF(end-of-list). + + @retval DMI_INVALID_HANDLE Handle is updated with first structure handle or + 0xFFFF(end-of-list). +**/ +EFI_STATUS +LibGetSmbiosStructure ( + IN OUT UINT16 *Handle, + OUT UINT8 **Buffer, + OUT UINT16 *Length + ); + +/** + Get SMBIOS structure for the given Handle in 64-bit table, + Handle is changed to the next handle or 0xFFFF when the end is + reached or the handle is not found. + + @param[in, out] Handle 0xFFFF: get the first structure + Others: get a structure according to this value. + @param[out] Buffer The pointer to the pointer to the structure. + @param[out] Length Length of the structure. + + @retval DMI_SUCCESS Handle is updated with next structure handle or + 0xFFFF(end-of-list). + + @retval DMI_INVALID_HANDLE Handle is updated with first structure handle or + 0xFFFF(end-of-list). +**/ +EFI_STATUS +LibGetSmbios64BitStructure ( + IN OUT UINT16 *Handle, + OUT UINT8 **Buffer, + OUT UINT16 *Length + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/PrintInfo.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/PrintInfo.c new file mode 100644 index 00000000..a89688c8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/PrintInfo.c @@ -0,0 +1,3456 @@ +/** @file + Module for clarifying the content of the smbios structure element information. + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
+ (C) Copyright 2015-2019 Hewlett Packard Enterprise Development LP
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDebug1CommandsLib.h" +#include "PrintInfo.h" +#include "LibSmbiosView.h" +#include "QueryTable.h" +#include "EventLogInfo.h" + + +// +// Get the certain bit of 'value' +// +#define BIT(value, bit) ((value) & ((UINT64) 1) << (bit)) + +// +// Check if above or equal to version +// +#define AE_SMBIOS_VERSION(MajorVersion, MinorVersion) \ + (SmbiosMajorVersion > (MajorVersion) || (SmbiosMajorVersion == (MajorVersion) && SmbiosMinorVersion >= (MinorVersion))) + +// +////////////////////////////////////////////////////////// +// Macros of print structure element, simplify coding. +// +#define PRINT_PENDING_STRING(pStruct, type, element) \ + do { \ + CHAR8 *StringBuf; \ + StringBuf = LibGetSmbiosString ((pStruct), (pStruct->type->element)); \ + ShellPrintEx(-1,-1,L"%a",#element); \ + ShellPrintEx(-1,-1,L": %a\n", (StringBuf != NULL) ? StringBuf: ""); \ + } while (0); + +#define PRINT_SMBIOS_STRING(pStruct, stringnumber, element) \ + do { \ + CHAR8 *StringBuf; \ + StringBuf = LibGetSmbiosString ((pStruct), (stringnumber)); \ + ShellPrintEx(-1,-1,L"%a",#element); \ + ShellPrintEx(-1,-1,L": %a\n", (StringBuf != NULL) ? StringBuf: ""); \ + } while (0); + +#define PRINT_STRUCT_VALUE(pStruct, type, element) \ + do { \ + ShellPrintEx(-1,-1,L"%a",#element); \ + ShellPrintEx(-1,-1,L": %u\n", (pStruct->type->element)); \ + } while (0); + +#define PRINT_STRUCT_VALUE_H(pStruct, type, element) \ + do { \ + ShellPrintEx(-1,-1,L"%a",#element); \ + ShellPrintEx(-1,-1,L": 0x%x\n", (pStruct->type->element)); \ + } while (0); + +#define PRINT_STRUCT_VALUE_LH(pStruct, type, element) \ + do { \ + ShellPrintEx(-1,-1,L"%a",#element); \ + ShellPrintEx(-1,-1,L": 0x%lx\n", (pStruct->type->element)); \ + } while (0); + +#define PRINT_BIT_FIELD(pStruct, type, element, size) \ + do { \ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_DUMP), gShellDebug1HiiHandle); \ + ShellPrintEx(-1,-1,L"%a",#element); \ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_SIZE), gShellDebug1HiiHandle, size); \ + DumpHex (0, 0, size, &(pStruct->type->element)); \ + } while (0); + +#define PRINT_SMBIOS_BIT_FIELD(pStruct, startaddress, element, size) \ + do { \ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_DUMP), gShellDebug1HiiHandle); \ + ShellPrintEx(-1,-1,L"%a",#element); \ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_SIZE), gShellDebug1HiiHandle, size); \ + DumpHex (0, 0, size, startaddress); \ + } while (0); + +// +///////////////////////////////////////// +// + +/** + Copy Length of Src buffer to Dest buffer, + add a NULL termination to Dest buffer. + + @param[in, out] Dest Destination buffer head. + @param[in] Src Source buffer head. + @param[in] Length Length of buffer to be copied. +**/ +VOID +MemToString ( + IN OUT VOID *Dest, + IN VOID *Src, + IN UINTN Length + ) +{ + UINT8 *SrcBuffer; + UINT8 *DestBuffer; + SrcBuffer = (UINT8 *) Src; + DestBuffer = (UINT8 *) Dest; + // + // copy byte by byte + // + while ((Length--)!=0) { + *DestBuffer++ = *SrcBuffer++; + } + // + // append a NULL terminator + // + *DestBuffer = '\0'; +} + +// +////////////////////////////////////////////// +// +// Functions below is to show the information +// + +/** + Print the info of EPS(Entry Point Structure). + + @param[in] SmbiosTable Pointer to the SMBIOS table entry point. + @param[in] Option Display option. +**/ +VOID +SmbiosPrintEPSInfo ( + IN SMBIOS_TABLE_ENTRY_POINT *SmbiosTable, + IN UINT8 Option + ) +{ + UINT8 Anchor[5]; + UINT8 InAnchor[6]; + + if (SmbiosTable == NULL) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_SMBIOSTABLE_NULL), gShellDebug1HiiHandle); + return ; + } + + if (Option == SHOW_NONE) { + return ; + } + + if (Option >= SHOW_NORMAL) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ENTRY_POINT_SIGN), gShellDebug1HiiHandle); + MemToString (Anchor, SmbiosTable->AnchorString, 4); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ANCHOR_STR), gShellDebug1HiiHandle, Anchor); + ShellPrintHiiEx(-1,-1,NULL, + STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_EPS_CHECKSUM), + gShellDebug1HiiHandle, + SmbiosTable->EntryPointStructureChecksum + ); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ENTRY_POINT_LEN), gShellDebug1HiiHandle, SmbiosTable->EntryPointLength); + ShellPrintHiiEx(-1,-1,NULL, + STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_VERSION), + gShellDebug1HiiHandle, + SmbiosTable->MajorVersion, + SmbiosTable->MinorVersion + ); + ShellPrintHiiEx(-1,-1,NULL, + STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_NUMBER_STRUCT), + gShellDebug1HiiHandle, + SmbiosTable->NumberOfSmbiosStructures + ); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_MAX_STRUCT_SIZE), gShellDebug1HiiHandle, SmbiosTable->MaxStructureSize); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_TABLE_ADDR), gShellDebug1HiiHandle, SmbiosTable->TableAddress); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_TABLE_LENGTH), gShellDebug1HiiHandle, SmbiosTable->TableLength); + + } + // + // If SHOW_ALL, also print followings. + // + if (Option >= SHOW_DETAIL) { + ShellPrintHiiEx(-1,-1,NULL, + STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ENTRY_POINT_REVISION), + gShellDebug1HiiHandle, + SmbiosTable->EntryPointRevision + ); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BCD_REVISION), gShellDebug1HiiHandle, SmbiosTable->SmbiosBcdRevision); + // + // Since raw data is not string, add a NULL terminater. + // + MemToString (InAnchor, SmbiosTable->IntermediateAnchorString, 5); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTER_ACHOR), gShellDebug1HiiHandle, InAnchor); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTER_CHECKSUM), gShellDebug1HiiHandle, SmbiosTable->IntermediateChecksum); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_FORMATTED_AREA), gShellDebug1HiiHandle); + DumpHex (2, 0, 5, SmbiosTable->FormattedArea); + } + + Print (L"\n"); +} + +/** + Print the info of 64-bit EPS(Entry Point Structure). + + @param[in] SmbiosTable Pointer to the SMBIOS table entry point. + @param[in] Option Display option. +**/ +VOID +Smbios64BitPrintEPSInfo ( + IN SMBIOS_TABLE_3_0_ENTRY_POINT *SmbiosTable, + IN UINT8 Option + ) +{ + UINT8 Anchor[5]; + + if (SmbiosTable == NULL) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_SMBIOSTABLE_NULL), gShellDebug1HiiHandle); + return ; + } + + if (Option == SHOW_NONE) { + return ; + } + + if (Option >= SHOW_NORMAL) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_64_BIT_ENTRY_POINT_SIGN), gShellDebug1HiiHandle); + + MemToString (Anchor, SmbiosTable->AnchorString, 5); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ANCHOR_STR), gShellDebug1HiiHandle, Anchor); + + ShellPrintHiiEx(-1,-1,NULL, + STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_EPS_CHECKSUM), + gShellDebug1HiiHandle, + SmbiosTable->EntryPointStructureChecksum + ); + + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ENTRY_POINT_LEN), gShellDebug1HiiHandle, SmbiosTable->EntryPointLength); + + ShellPrintHiiEx(-1,-1,NULL, + STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_VERSION), + gShellDebug1HiiHandle, + SmbiosTable->MajorVersion, + SmbiosTable->MinorVersion + ); + + ShellPrintHiiEx(-1,-1,NULL, + STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_DOCREV), + gShellDebug1HiiHandle, + SmbiosTable->DocRev + ); + + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_TABLE_MAX_SIZE), gShellDebug1HiiHandle, SmbiosTable->TableMaximumSize); + + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_TABLE_ADDR), gShellDebug1HiiHandle, SmbiosTable->TableAddress); + + } + // + // If SHOW_ALL, also print followings. + // + if (Option >= SHOW_DETAIL) { + ShellPrintHiiEx(-1,-1,NULL, + STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ENTRY_POINT_REVISION), + gShellDebug1HiiHandle, + SmbiosTable->EntryPointRevision + ); + } + + Print (L"\n"); +} + +/** + This function print the content of the structure pointed by Struct. + + @param[in] Struct Point to the structure to be printed. + @param[in] Option Print option of information detail. + + @retval EFI_SUCCESS Successfully Printing this function. + @retval EFI_INVALID_PARAMETER Invalid Structure. + @retval EFI_UNSUPPORTED Unsupported. +**/ +EFI_STATUS +SmbiosPrintStructure ( + IN SMBIOS_STRUCTURE_POINTER *Struct, + IN UINT8 Option + ) +{ + UINT8 Index; + UINT8 Index2; + UINT8 *Buffer; + + if (Struct == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Option == SHOW_NONE) { + return EFI_SUCCESS; + } + + Buffer = (UINT8 *) (UINTN) (Struct->Raw); + + // + // Display structure header + // + DisplayStructureTypeInfo (Struct->Hdr->Type, SHOW_DETAIL); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_FORMAT_PART_LEN), gShellDebug1HiiHandle, Struct->Hdr->Length); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_STRUCT_HANDLE), gShellDebug1HiiHandle, Struct->Hdr->Handle); + + if (Option == SHOW_OUTLINE) { + return EFI_SUCCESS; + } + + switch (Struct->Hdr->Type) { + // + // BIOS Information (Type 0) + // + case 0: + PRINT_PENDING_STRING (Struct, Type0, Vendor); + PRINT_PENDING_STRING (Struct, Type0, BiosVersion); + PRINT_STRUCT_VALUE_H (Struct, Type0, BiosSegment); + PRINT_PENDING_STRING (Struct, Type0, BiosReleaseDate); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BIOS_SIZE), gShellDebug1HiiHandle, 64 * (Struct->Type0->BiosSize + 1)); + + DisplayBiosCharacteristics (ReadUnaligned64 ((UINT64 *) (UINTN) &(Struct->Type0->BiosCharacteristics)), Option); + + if (Struct->Hdr->Length > 0x12) { + DisplayBiosCharacteristicsExt1 (Struct->Type0->BIOSCharacteristicsExtensionBytes[0], Option); + } + if (Struct->Hdr->Length > 0x13) { + DisplayBiosCharacteristicsExt2 (Struct->Type0->BIOSCharacteristicsExtensionBytes[1], Option); + } + + if (AE_SMBIOS_VERSION (0x2, 0x4) && (Struct->Hdr->Length > 0x14)) { + PRINT_STRUCT_VALUE (Struct, Type0, SystemBiosMajorRelease); + PRINT_STRUCT_VALUE (Struct, Type0, SystemBiosMinorRelease); + PRINT_STRUCT_VALUE (Struct, Type0, EmbeddedControllerFirmwareMajorRelease); + PRINT_STRUCT_VALUE (Struct, Type0, EmbeddedControllerFirmwareMinorRelease); + } + if (AE_SMBIOS_VERSION (0x3, 0x1) && (Struct->Hdr->Length > 0x18)) { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_EXTENDED_BIOS_SIZE), + gShellDebug1HiiHandle, + Struct->Type0->ExtendedBiosSize.Size, + (Struct->Type0->ExtendedBiosSize.Unit == 0x0) ? L"MB": L"GB" + ); + } + break; + + // + // System Information (Type 1) + // + case 1: + PRINT_PENDING_STRING (Struct, Type1, Manufacturer); + PRINT_PENDING_STRING (Struct, Type1, ProductName); + PRINT_PENDING_STRING (Struct, Type1, Version); + PRINT_PENDING_STRING (Struct, Type1, SerialNumber); + PRINT_BIT_FIELD (Struct, Type1, Uuid, 16); + DisplaySystemWakeupType (Struct->Type1->WakeUpType, Option); + if (AE_SMBIOS_VERSION (0x2, 0x4) && (Struct->Hdr->Length > 0x19)) { + PRINT_PENDING_STRING (Struct, Type1, SKUNumber); + PRINT_PENDING_STRING (Struct, Type1, Family); + } + + break; + + // + // Baseboard Information (Type 2) + // + case 2: + PRINT_PENDING_STRING (Struct, Type2, Manufacturer); + PRINT_PENDING_STRING (Struct, Type2, ProductName); + PRINT_PENDING_STRING (Struct, Type2, Version); + PRINT_PENDING_STRING (Struct, Type2, SerialNumber); + if (Struct->Hdr->Length > 0x8) { + PRINT_PENDING_STRING (Struct, Type2, AssetTag); + DisplayBaseBoardFeatureFlags (*(UINT8 *) &Struct->Type2->FeatureFlag, Option); + PRINT_PENDING_STRING (Struct, Type2, LocationInChassis); + PRINT_STRUCT_VALUE_H (Struct, Type2, ChassisHandle); + DisplayBaseBoardBoardType (Struct->Type2->BoardType, Option); + } + break; + + // + // System Enclosure (Type 3) + // + case 3: + PRINT_PENDING_STRING (Struct, Type3, Manufacturer); + PRINT_STRUCT_VALUE (Struct, Type3, Type); + DisplaySystemEnclosureType (Struct->Type3->Type, Option); + PRINT_PENDING_STRING (Struct, Type3, Version); + PRINT_PENDING_STRING (Struct, Type3, SerialNumber); + PRINT_PENDING_STRING (Struct, Type3, AssetTag); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BOOTUP_STATE), gShellDebug1HiiHandle); + DisplaySystemEnclosureStatus (Struct->Type3->BootupState, Option); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_POWER_SUPPLY_STATE), gShellDebug1HiiHandle); + DisplaySystemEnclosureStatus (Struct->Type3->PowerSupplyState, Option); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_THERMAL_STATE), gShellDebug1HiiHandle); + DisplaySystemEnclosureStatus (Struct->Type3->ThermalState, Option); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_SECURITY_STATUS), gShellDebug1HiiHandle); + DisplaySESecurityStatus (Struct->Type3->SecurityStatus, Option); + if (AE_SMBIOS_VERSION (0x2, 0x3)) { + if (Struct->Hdr->Length > 0xD) { + PRINT_BIT_FIELD (Struct, Type3, OemDefined, 4); + } + if (Struct->Hdr->Length > 0x11) { + PRINT_STRUCT_VALUE (Struct, Type3, Height); + } + if (Struct->Hdr->Length > 0x12) { + PRINT_STRUCT_VALUE (Struct, Type3, NumberofPowerCords); + } + if (Struct->Hdr->Length > 0x13) { + PRINT_STRUCT_VALUE (Struct, Type3, ContainedElementCount); + } + if (Struct->Hdr->Length > 0x14) { + PRINT_STRUCT_VALUE (Struct, Type3, ContainedElementRecordLength); + } + if (Struct->Hdr->Length > 0x15) { + for (Index = 0; Index < Struct->Type3->ContainedElementCount; Index++) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_CONTAINED_ELEMENT), gShellDebug1HiiHandle, Index+1); + for (Index2 = 0; Index2< Struct->Type3->ContainedElementRecordLength; Index2++) { + Print (L"%02X ", Buffer[0x15 + (Index * Struct->Type3->ContainedElementRecordLength) + Index2]); + } + Print (L"\n"); + } + } + } + if (AE_SMBIOS_VERSION (0x2, 0x7) && (Struct->Hdr->Length > 0x13)) { + if (Struct->Hdr->Length > (0x15 + (Struct->Type3->ContainedElementCount * Struct->Type3->ContainedElementRecordLength))) { + PRINT_SMBIOS_STRING (Struct, Buffer[0x15 + (Struct->Type3->ContainedElementCount * Struct->Type3->ContainedElementRecordLength)], SKUNumber); + } + } + break; + + // + // Processor Information (Type 4) + // + case 4: + PRINT_SMBIOS_STRING (Struct, Struct->Type4->Socket, SocketDesignation) + DisplayProcessorType (Struct->Type4->ProcessorType, Option); + if (AE_SMBIOS_VERSION (0x2, 0x6) && (Struct->Hdr->Length > 0x28) && + (Struct->Type4->ProcessorFamily == 0xFE)) { + // + // Get family from ProcessorFamily2 field + // + DisplayProcessorFamily2 (Struct->Type4->ProcessorFamily2, Option); + } else { + DisplayProcessorFamily (Struct->Type4->ProcessorFamily, Option); + } + PRINT_PENDING_STRING (Struct, Type4, ProcessorManufacturer); + PRINT_BIT_FIELD (Struct, Type4, ProcessorId, 8); + PRINT_PENDING_STRING (Struct, Type4, ProcessorVersion); + DisplayProcessorVoltage (*(UINT8 *) &(Struct->Type4->Voltage), Option); + PRINT_STRUCT_VALUE (Struct, Type4, ExternalClock); + PRINT_STRUCT_VALUE (Struct, Type4, MaxSpeed); + PRINT_STRUCT_VALUE (Struct, Type4, CurrentSpeed); + DisplayProcessorStatus (Struct->Type4->Status, Option); + DisplayProcessorUpgrade (Struct->Type4->ProcessorUpgrade, Option); + PRINT_STRUCT_VALUE_H (Struct, Type4, L1CacheHandle); + PRINT_STRUCT_VALUE_H (Struct, Type4, L2CacheHandle); + PRINT_STRUCT_VALUE_H (Struct, Type4, L3CacheHandle); + if (AE_SMBIOS_VERSION (0x2, 0x3) && (Struct->Hdr->Length > 0x20)) { + PRINT_PENDING_STRING (Struct, Type4, SerialNumber); + PRINT_PENDING_STRING (Struct, Type4, AssetTag); + PRINT_PENDING_STRING (Struct, Type4, PartNumber); + } + if (AE_SMBIOS_VERSION (0x2, 0x5) && (Struct->Hdr->Length > 0x23)) { + PRINT_STRUCT_VALUE (Struct, Type4, CoreCount); + PRINT_STRUCT_VALUE (Struct, Type4, EnabledCoreCount); + PRINT_STRUCT_VALUE (Struct, Type4, ThreadCount); + DisplayProcessorCharacteristics (Struct->Type4->ProcessorCharacteristics, Option); + } + if ((SmbiosMajorVersion >= 0x3) && (Struct->Hdr->Length > 0x2A)) { + PRINT_STRUCT_VALUE (Struct, Type4, CoreCount2); + PRINT_STRUCT_VALUE (Struct, Type4, EnabledCoreCount2); + PRINT_STRUCT_VALUE (Struct, Type4, ThreadCount2); + } + break; + + // + // Memory Controller Information (Type 5) + // + case 5: + { + UINT8 SlotNum; + SlotNum = Struct->Type5->AssociatedMemorySlotNum; + + DisplayMcErrorDetectMethod (Struct->Type5->ErrDetectMethod, Option); + DisplayMcErrorCorrectCapability (*(UINT8 *) &(Struct->Type5->ErrCorrectCapability), Option); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_SUPOPRT), gShellDebug1HiiHandle); + DisplayMcInterleaveSupport (Struct->Type5->SupportInterleave, Option); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_CURRENT), gShellDebug1HiiHandle); + DisplayMcInterleaveSupport (Struct->Type5->CurrentInterleave, Option); + DisplayMaxMemoryModuleSize (Struct->Type5->MaxMemoryModuleSize, SlotNum, Option); + DisplayMcMemorySpeeds (*(UINT16 *) &(Struct->Type5->SupportSpeed), Option); + DisplayMmMemoryType (Struct->Type5->SupportMemoryType, Option); + DisplayMemoryModuleVoltage (Struct->Type5->MemoryModuleVoltage, Option); + PRINT_STRUCT_VALUE (Struct, Type5, AssociatedMemorySlotNum); + // + // According to SMBIOS Specification, offset 0x0F + // + DisplayMemoryModuleConfigHandles ((UINT16 *) (&Buffer[0x0F]), SlotNum, Option); + DisplayMcErrorCorrectCapability (Buffer[0x0F + 2 * SlotNum], Option); + } + break; + + // + // Memory Module Information (Type 6) + // + case 6: + PRINT_PENDING_STRING (Struct, Type6, SocketDesignation); + DisplayMmBankConnections (Struct->Type6->BankConnections, Option); + PRINT_STRUCT_VALUE (Struct, Type6, CurrentSpeed); + DisplayMmMemoryType (*(UINT16 *) &(Struct->Type6->CurrentMemoryType), Option); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INSTALLED), gShellDebug1HiiHandle); + DisplayMmMemorySize (*(UINT8 *) &(Struct->Type6->InstalledSize), Option); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ENABLED), gShellDebug1HiiHandle); + DisplayMmMemorySize (*(UINT8 *) &(Struct->Type6->EnabledSize), Option); + DisplayMmErrorStatus (Struct->Type6->ErrorStatus, Option); + break; + + // + // Cache Information (Type 7) + // + case 7: + PRINT_PENDING_STRING (Struct, Type7, SocketDesignation); + DisplayCacheConfiguration (Struct->Type7->CacheConfiguration, Option); + PRINT_STRUCT_VALUE_H (Struct, Type7, MaximumCacheSize); + PRINT_STRUCT_VALUE_H (Struct, Type7, InstalledSize); + PRINT_STRUCT_VALUE_H (Struct, Type7, SupportedSRAMType); + PRINT_STRUCT_VALUE_H (Struct, Type7, CurrentSRAMType); + DisplayCacheSRAMType (ReadUnaligned16 ((UINT16 *) (UINTN) &(Struct->Type7->CurrentSRAMType)), Option); + PRINT_STRUCT_VALUE_H (Struct, Type7, CacheSpeed); + DisplayCacheErrCorrectingType (Struct->Type7->ErrorCorrectionType, Option); + DisplayCacheSystemCacheType (Struct->Type7->SystemCacheType, Option); + DisplayCacheAssociativity (Struct->Type7->Associativity, Option); + if (AE_SMBIOS_VERSION (0x3, 0x1) && (Struct->Hdr->Length > 0x13)) { + PRINT_STRUCT_VALUE_H (Struct, Type7, MaximumCacheSize2); + PRINT_STRUCT_VALUE_H (Struct, Type7, InstalledSize2); + } + break; + + // + // Port Connector Information (Type 8) + // + case 8: + PRINT_PENDING_STRING (Struct, Type8, InternalReferenceDesignator); + Print (L"Internal "); + DisplayPortConnectorType (Struct->Type8->InternalConnectorType, Option); + PRINT_PENDING_STRING (Struct, Type8, ExternalReferenceDesignator); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_EXTERNAL), gShellDebug1HiiHandle); + DisplayPortConnectorType (Struct->Type8->ExternalConnectorType, Option); + DisplayPortType (Struct->Type8->PortType, Option); + break; + + // + // System Slots (Type 9) + // + case 9: + { + MISC_SLOT_PEER_GROUP *PeerGroupPtr; + UINT8 PeerGroupCount; + + PRINT_PENDING_STRING (Struct, Type9, SlotDesignation); + DisplaySystemSlotType (Struct->Type9->SlotType, Option); + DisplaySystemSlotDataBusWidth (Struct->Type9->SlotDataBusWidth, Option); + DisplaySystemSlotCurrentUsage (Struct->Type9->CurrentUsage, Option); + DisplaySystemSlotLength (Struct->Type9->SlotLength, Option); + DisplaySystemSlotId ( + Struct->Type9->SlotID, + Struct->Type9->SlotType, + Option + ); + DisplaySlotCharacteristics1 (*(UINT8 *) &(Struct->Type9->SlotCharacteristics1), Option); + DisplaySlotCharacteristics2 (*(UINT8 *) &(Struct->Type9->SlotCharacteristics2), Option); + if (AE_SMBIOS_VERSION (0x2, 0x6) && (Struct->Hdr->Length > 0xD)) { + PRINT_STRUCT_VALUE_H (Struct, Type9, SegmentGroupNum); + PRINT_STRUCT_VALUE_H (Struct, Type9, BusNum); + PRINT_STRUCT_VALUE_H (Struct, Type9, DevFuncNum); + } + if (AE_SMBIOS_VERSION (0x3, 0x2)) { + if (Struct->Hdr->Length > 0x11) { + PRINT_STRUCT_VALUE (Struct, Type9, DataBusWidth); + } + if (Struct->Hdr->Length > 0x12) { + PRINT_STRUCT_VALUE (Struct, Type9, PeerGroupingCount); + + PeerGroupCount = Struct->Type9->PeerGroupingCount; + PeerGroupPtr = Struct->Type9->PeerGroups; + for (Index = 0; Index < PeerGroupCount; Index++) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_SLOT_PEER_GROUPS), gShellDebug1HiiHandle, Index + 1); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_SEGMENT_GROUP_NUM), gShellDebug1HiiHandle, PeerGroupPtr[Index].SegmentGroupNum); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BUS_NUM), gShellDebug1HiiHandle, PeerGroupPtr[Index].BusNum); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_DEV_FUNC_NUM), gShellDebug1HiiHandle, PeerGroupPtr[Index].DevFuncNum); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_DATA_BUS_WIDTH), gShellDebug1HiiHandle, PeerGroupPtr[Index].DataBusWidth); + } + } + } + } + break; + + // + // On Board Devices Information (Type 10) + // + case 10: + { + UINTN NumOfDevice; + NumOfDevice = (Struct->Type10->Hdr.Length - sizeof (SMBIOS_STRUCTURE)) / (2 * sizeof (UINT8)); + for (Index = 0; Index < NumOfDevice; Index++) { + ShellPrintEx(-1,-1,(((Struct->Type10->Device[Index].DeviceType) & 0x80) != 0) ? L"Device Enabled\n": L"Device Disabled\n"); + DisplayOnboardDeviceTypes ((Struct->Type10->Device[Index].DeviceType) & 0x7F, Option); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_DESC_STRING), gShellDebug1HiiHandle); + ShellPrintEx(-1,-1,L"%a\n",LibGetSmbiosString (Struct, Struct->Type10->Device[Index].DescriptionString)); + } + } + break; + + // + // Oem Strings (Type 11) + // + case 11: + PRINT_STRUCT_VALUE (Struct, Type11, StringCount); + for (Index = 1; Index <= Struct->Type11->StringCount; Index++) { + ShellPrintEx(-1,-1,L"%a\n", LibGetSmbiosString (Struct, Index)); + } + break; + + // + // System Configuration Options (Type 12) + // + case 12: + PRINT_STRUCT_VALUE (Struct, Type12, StringCount); + for (Index = 1; Index <= Struct->Type12->StringCount; Index++) { + ShellPrintEx(-1,-1,L"%a\n", LibGetSmbiosString (Struct, Index)); + } + break; + + // + // BIOS Language Information (Type 13) + // + case 13: + PRINT_STRUCT_VALUE (Struct, Type13, InstallableLanguages); + PRINT_STRUCT_VALUE (Struct, Type13, Flags); + PRINT_BIT_FIELD (Struct, Type13, Reserved, 15); + PRINT_PENDING_STRING (Struct, Type13, CurrentLanguages); + break; + + // + // Group Associations (Type 14) + // + case 14: + { + UINT8 NumOfItem; + NumOfItem = (Struct->Type14->Hdr.Length - 5) / 3; + PRINT_PENDING_STRING (Struct, Type14, GroupName); + for (Index = 0; Index < NumOfItem; Index++) { + ShellPrintEx(-1,-1,L"ItemType %u: %u\n", Index + 1, Struct->Type14->Group[Index].ItemType); + ShellPrintEx(-1,-1,L"ItemHandle %u: %u\n", Index + 1, Struct->Type14->Group[Index].ItemHandle); + } + } + break; + + // + // System Event Log (Type 15) + // + case 15: + { + EVENT_LOG_TYPE *Ptr; + UINT8 Count; + UINT8 *AccessMethodAddress; + + PRINT_STRUCT_VALUE_H (Struct, Type15, LogAreaLength); + PRINT_STRUCT_VALUE_H (Struct, Type15, LogHeaderStartOffset); + PRINT_STRUCT_VALUE_H (Struct, Type15, LogDataStartOffset); + DisplaySELAccessMethod (Struct->Type15->AccessMethod, Option); + PRINT_STRUCT_VALUE_H (Struct, Type15, AccessMethodAddress); + DisplaySELLogStatus (Struct->Type15->LogStatus, Option); + PRINT_STRUCT_VALUE_H (Struct, Type15, LogChangeToken); + DisplaySysEventLogHeaderFormat (Struct->Type15->LogHeaderFormat, Option); + PRINT_STRUCT_VALUE_H (Struct, Type15, NumberOfSupportedLogTypeDescriptors); + PRINT_STRUCT_VALUE_H (Struct, Type15, LengthOfLogTypeDescriptor); + + Count = Struct->Type15->NumberOfSupportedLogTypeDescriptors; + if (Count > 0) { + Ptr = Struct->Type15->EventLogTypeDescriptors; + + // + // Display all Event Log type descriptors supported by system + // + for (Index = 0; Index < Count; Index++, Ptr++) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_SUPOPRTED_EVENT), gShellDebug1HiiHandle, Index + 1); + DisplaySELTypes (Ptr->LogType, Option); + DisplaySELVarDataFormatType (Ptr->DataFormatType, Option); + } + + if (Option >= SHOW_DETAIL) { + switch (Struct->Type15->AccessMethod) { + case 03: + AccessMethodAddress = (UINT8 *) (UINTN) (Struct->Type15->AccessMethodAddress); + break; + + case 00: + case 01: + case 02: + case 04: + default: + ShellPrintHiiEx(-1,-1,NULL, + STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ACCESS_METHOD_NOT_SUPOPRTED), + gShellDebug1HiiHandle, + Struct->Type15->AccessMethod + ); + return EFI_UNSUPPORTED; + } + // + // Display Event Log Header + // + // Starting offset (or index) within the nonvolatile storage + // of the event-log's header, from the Access Method Address + // + DisplaySysEventLogHeader ( + Struct->Type15->LogHeaderFormat, + AccessMethodAddress + Struct->Type15->LogHeaderStartOffset + ); + + // + // Display all Event Log data + // + // Starting offset (or index) within the nonvolatile storage + // of the event-log's first data byte, from the Access Method Address(0x14) + // + DisplaySysEventLogData ( + AccessMethodAddress + Struct->Type15->LogDataStartOffset, + (UINT16) + ( + Struct->Type15->LogAreaLength - + (Struct->Type15->LogDataStartOffset - Struct->Type15->LogHeaderStartOffset) + ) + ); + } + + } + } + break; + + // + // Physical Memory Array (Type 16) + // + case 16: + DisplayPMALocation (Struct->Type16->Location, Option); + DisplayPMAUse (Struct->Type16->Use, Option); + DisplayPMAErrorCorrectionTypes ( + Struct->Type16->MemoryErrorCorrection, + Option + ); + PRINT_STRUCT_VALUE_H (Struct, Type16, MaximumCapacity); + PRINT_STRUCT_VALUE_H (Struct, Type16, MemoryErrorInformationHandle); + PRINT_STRUCT_VALUE_H (Struct, Type16, NumberOfMemoryDevices); + if (AE_SMBIOS_VERSION (0x2, 0x7) && Struct->Hdr->Length > 0xF) { + PRINT_STRUCT_VALUE_LH (Struct, Type16, ExtendedMaximumCapacity); + } + break; + + // + // Memory Device (Type 17) + // + case 17: + PRINT_STRUCT_VALUE_H (Struct, Type17, MemoryArrayHandle); + PRINT_STRUCT_VALUE_H (Struct, Type17, MemoryErrorInformationHandle); + PRINT_STRUCT_VALUE_H (Struct, Type17, TotalWidth); + PRINT_STRUCT_VALUE_H (Struct, Type17, DataWidth); + PRINT_STRUCT_VALUE (Struct, Type17, Size); + DisplayMemoryDeviceFormFactor (Struct->Type17->FormFactor, Option); + PRINT_STRUCT_VALUE_H (Struct, Type17, DeviceSet); + PRINT_PENDING_STRING (Struct, Type17, DeviceLocator); + PRINT_PENDING_STRING (Struct, Type17, BankLocator); + DisplayMemoryDeviceType (Struct->Type17->MemoryType, Option); + DisplayMemoryDeviceTypeDetail (ReadUnaligned16 ((UINT16 *) (UINTN) &(Struct->Type17->TypeDetail)), Option); + PRINT_STRUCT_VALUE_H (Struct, Type17, Speed); + PRINT_PENDING_STRING (Struct, Type17, Manufacturer); + PRINT_PENDING_STRING (Struct, Type17, SerialNumber); + PRINT_PENDING_STRING (Struct, Type17, AssetTag); + PRINT_PENDING_STRING (Struct, Type17, PartNumber); + if (AE_SMBIOS_VERSION (0x2, 0x6) && (Struct->Hdr->Length > 0x1B)) { + PRINT_STRUCT_VALUE_H (Struct, Type17, Attributes); + } + if (AE_SMBIOS_VERSION (0x2, 0x7) && (Struct->Hdr->Length > 0x1C)) { + PRINT_STRUCT_VALUE (Struct, Type17, ExtendedSize); + PRINT_STRUCT_VALUE_H (Struct, Type17, ConfiguredMemoryClockSpeed); + } + if (AE_SMBIOS_VERSION (0x2, 0x8) && (Struct->Hdr->Length > 0x22)) { + PRINT_STRUCT_VALUE (Struct, Type17, MinimumVoltage); + PRINT_STRUCT_VALUE (Struct, Type17, MaximumVoltage); + PRINT_STRUCT_VALUE (Struct, Type17, ConfiguredVoltage); + } + if (AE_SMBIOS_VERSION (0x3, 0x2)) { + if (Struct->Hdr->Length > 0x28) { + DisplayMemoryDeviceMemoryTechnology (Struct->Type17->MemoryTechnology, Option); + DisplayMemoryDeviceMemoryOperatingModeCapability (Struct->Type17->MemoryOperatingModeCapability.Uint16, Option); + PRINT_PENDING_STRING (Struct, Type17, FirmwareVersion); + PRINT_STRUCT_VALUE_H (Struct, Type17, ModuleManufacturerID); + PRINT_STRUCT_VALUE_H (Struct, Type17, ModuleProductID); + PRINT_STRUCT_VALUE_H (Struct, Type17, MemorySubsystemControllerManufacturerID); + PRINT_STRUCT_VALUE_H (Struct, Type17, MemorySubsystemControllerProductID); + } + if (Struct->Hdr->Length > 0x34) { + PRINT_STRUCT_VALUE_LH (Struct, Type17, NonVolatileSize); + } + if (Struct->Hdr->Length > 0x3C) { + PRINT_STRUCT_VALUE_LH (Struct, Type17, VolatileSize); + } + if (Struct->Hdr->Length > 0x44) { + PRINT_STRUCT_VALUE_LH (Struct, Type17, CacheSize); + } + if (Struct->Hdr->Length > 0x4C) { + PRINT_STRUCT_VALUE_LH (Struct, Type17, LogicalSize); + } + } + break; + + // + // 32-bit Memory Error Information (Type 18) + // + case 18: + DisplayMemoryErrorType (Struct->Type18->ErrorType, Option); + DisplayMemoryErrorGranularity ( + Struct->Type18->ErrorGranularity, + Option + ); + DisplayMemoryErrorOperation (Struct->Type18->ErrorOperation, Option); + PRINT_STRUCT_VALUE_H (Struct, Type18, VendorSyndrome); + PRINT_STRUCT_VALUE_H (Struct, Type18, MemoryArrayErrorAddress); + PRINT_STRUCT_VALUE_H (Struct, Type18, DeviceErrorAddress); + PRINT_STRUCT_VALUE_H (Struct, Type18, ErrorResolution); + break; + + // + // Memory Array Mapped Address (Type 19) + // + case 19: + PRINT_STRUCT_VALUE_H (Struct, Type19, StartingAddress); + PRINT_STRUCT_VALUE_H (Struct, Type19, EndingAddress); + PRINT_STRUCT_VALUE_H (Struct, Type19, MemoryArrayHandle); + PRINT_STRUCT_VALUE_H (Struct, Type19, PartitionWidth); + if (AE_SMBIOS_VERSION (0x2, 0x7) && (Struct->Hdr->Length > 0xF)) { + PRINT_STRUCT_VALUE_LH (Struct, Type19, ExtendedStartingAddress); + PRINT_STRUCT_VALUE_LH (Struct, Type19, ExtendedEndingAddress); + } + break; + + // + // Memory Device Mapped Address (Type 20) + // + case 20: + PRINT_STRUCT_VALUE_H (Struct, Type20, StartingAddress); + PRINT_STRUCT_VALUE_H (Struct, Type20, EndingAddress); + PRINT_STRUCT_VALUE_H (Struct, Type20, MemoryDeviceHandle); + PRINT_STRUCT_VALUE_H (Struct, Type20, MemoryArrayMappedAddressHandle); + PRINT_STRUCT_VALUE_H (Struct, Type20, PartitionRowPosition); + PRINT_STRUCT_VALUE_H (Struct, Type20, InterleavePosition); + PRINT_STRUCT_VALUE_H (Struct, Type20, InterleavedDataDepth); + if (AE_SMBIOS_VERSION (0x2, 0x7) && (Struct->Hdr->Length > 0x13)) { + PRINT_STRUCT_VALUE_LH (Struct, Type19, ExtendedStartingAddress); + PRINT_STRUCT_VALUE_LH (Struct, Type19, ExtendedEndingAddress); + } + break; + + // + // Built-in Pointing Device (Type 21) + // + case 21: + DisplayPointingDeviceType (Struct->Type21->Type, Option); + DisplayPointingDeviceInterface (Struct->Type21->Interface, Option); + PRINT_STRUCT_VALUE (Struct, Type21, NumberOfButtons); + break; + + // + // Portable Battery (Type 22) + // + case 22: + PRINT_PENDING_STRING (Struct, Type22, Location); + PRINT_PENDING_STRING (Struct, Type22, Manufacturer); + PRINT_PENDING_STRING (Struct, Type22, ManufactureDate); + PRINT_PENDING_STRING (Struct, Type22, SerialNumber); + PRINT_PENDING_STRING (Struct, Type22, DeviceName); + DisplayPBDeviceChemistry ( + Struct->Type22->DeviceChemistry, + Option + ); + PRINT_STRUCT_VALUE_H (Struct, Type22, DeviceCapacity); + PRINT_STRUCT_VALUE_H (Struct, Type22, DesignVoltage); + PRINT_PENDING_STRING (Struct, Type22, SBDSVersionNumber); + PRINT_STRUCT_VALUE_H (Struct, Type22, MaximumErrorInBatteryData); + PRINT_STRUCT_VALUE_H (Struct, Type22, SBDSSerialNumber); + DisplaySBDSManufactureDate ( + Struct->Type22->SBDSManufactureDate, + Option + ); + PRINT_PENDING_STRING (Struct, Type22, SBDSDeviceChemistry); + PRINT_STRUCT_VALUE_H (Struct, Type22, DesignCapacityMultiplier); + PRINT_STRUCT_VALUE_H (Struct, Type22, OEMSpecific); + break; + + // + // System Reset (Type 23) + // + case 23: + DisplaySystemResetCapabilities ( + Struct->Type23->Capabilities, + Option + ); + PRINT_STRUCT_VALUE_H (Struct, Type23, ResetCount); + PRINT_STRUCT_VALUE_H (Struct, Type23, ResetLimit); + PRINT_STRUCT_VALUE_H (Struct, Type23, TimerInterval); + PRINT_STRUCT_VALUE_H (Struct, Type23, Timeout); + break; + + // + // Hardware Security (Type 24) + // + case 24: + DisplayHardwareSecuritySettings ( + Struct->Type24->HardwareSecuritySettings, + Option + ); + break; + + // + // System Power Controls (Type 25) + // + case 25: + PRINT_STRUCT_VALUE_H (Struct, Type25, NextScheduledPowerOnMonth); + PRINT_STRUCT_VALUE_H (Struct, Type25, NextScheduledPowerOnDayOfMonth); + PRINT_STRUCT_VALUE_H (Struct, Type25, NextScheduledPowerOnHour); + PRINT_STRUCT_VALUE_H (Struct, Type25, NextScheduledPowerOnMinute); + PRINT_STRUCT_VALUE_H (Struct, Type25, NextScheduledPowerOnSecond); + break; + + // + // Voltage Probe (Type 26) + // + case 26: + PRINT_PENDING_STRING (Struct, Type26, Description); + DisplayVPLocation (*(UINT8 *) &(Struct->Type26->LocationAndStatus), Option); + DisplayVPStatus (*(UINT8 *) &(Struct->Type26->LocationAndStatus), Option); + PRINT_STRUCT_VALUE_H (Struct, Type26, MaximumValue); + PRINT_STRUCT_VALUE_H (Struct, Type26, MinimumValue); + PRINT_STRUCT_VALUE_H (Struct, Type26, Resolution); + PRINT_STRUCT_VALUE_H (Struct, Type26, Tolerance); + PRINT_STRUCT_VALUE_H (Struct, Type26, Accuracy); + PRINT_STRUCT_VALUE_H (Struct, Type26, OEMDefined); + PRINT_STRUCT_VALUE_H (Struct, Type26, NominalValue); + break; + + // + // Cooling Device (Type 27) + // + case 27: + PRINT_STRUCT_VALUE_H (Struct, Type27, TemperatureProbeHandle); + DisplayCoolingDeviceStatus (*(UINT8 *) &(Struct->Type27->DeviceTypeAndStatus), Option); + DisplayCoolingDeviceType (*(UINT8 *) &(Struct->Type27->DeviceTypeAndStatus), Option); + PRINT_STRUCT_VALUE_H (Struct, Type27, CoolingUnitGroup); + PRINT_STRUCT_VALUE_H (Struct, Type27, OEMDefined); + PRINT_STRUCT_VALUE_H (Struct, Type27, NominalSpeed); + if (AE_SMBIOS_VERSION (0x2, 0x7) && (Struct->Hdr->Length > 0xE)) { + PRINT_PENDING_STRING (Struct, Type27, Description); + } + break; + + // + // Temperature Probe (Type 28) + // + case 28: + PRINT_PENDING_STRING (Struct, Type28, Description); + DisplayTemperatureProbeStatus (*(UINT8 *) &(Struct->Type28->LocationAndStatus), Option); + DisplayTemperatureProbeLoc (*(UINT8 *) &(Struct->Type28->LocationAndStatus), Option); + PRINT_STRUCT_VALUE_H (Struct, Type28, MaximumValue); + PRINT_STRUCT_VALUE_H (Struct, Type28, MinimumValue); + PRINT_STRUCT_VALUE_H (Struct, Type28, Resolution); + PRINT_STRUCT_VALUE_H (Struct, Type28, Tolerance); + PRINT_STRUCT_VALUE_H (Struct, Type28, Accuracy); + PRINT_STRUCT_VALUE_H (Struct, Type28, OEMDefined); + PRINT_STRUCT_VALUE_H (Struct, Type28, NominalValue); + break; + + // + // Electrical Current Probe (Type 29) + // + case 29: + PRINT_PENDING_STRING (Struct, Type29, Description); + DisplayECPStatus (*(UINT8 *) &(Struct->Type29->LocationAndStatus), Option); + DisplayECPLoc (*(UINT8 *) &(Struct->Type29->LocationAndStatus), Option); + PRINT_STRUCT_VALUE_H (Struct, Type29, MaximumValue); + PRINT_STRUCT_VALUE_H (Struct, Type29, MinimumValue); + PRINT_STRUCT_VALUE_H (Struct, Type29, Resolution); + PRINT_STRUCT_VALUE_H (Struct, Type29, Tolerance); + PRINT_STRUCT_VALUE_H (Struct, Type29, Accuracy); + PRINT_STRUCT_VALUE_H (Struct, Type29, OEMDefined); + PRINT_STRUCT_VALUE_H (Struct, Type29, NominalValue); + break; + + // + // Out-of-Band Remote Access (Type 30) + // + case 30: + PRINT_PENDING_STRING (Struct, Type30, ManufacturerName); + DisplayOBRAConnections (Struct->Type30->Connections, Option); + break; + + // + // Boot Integrity Services (BIS) Entry Point (Type 31) + // + case 31: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_STRUCT_TYPE31), gShellDebug1HiiHandle); + break; + + // + // System Boot Information (Type 32) + // + case 32: + PRINT_BIT_FIELD (Struct, Type32, Reserved, 6); + DisplaySystemBootStatus (Struct->Type32->BootStatus, Option); + break; + + // + // 64-Bit Memory Error Information (Type 33) + // + case 33: + DisplayMemoryErrorType (Struct->Type33->ErrorType, Option); + DisplayMemoryErrorGranularity ( + Struct->Type33->ErrorGranularity, + Option + ); + DisplayMemoryErrorOperation (Struct->Type33->ErrorOperation, Option); + PRINT_STRUCT_VALUE_H (Struct, Type33, VendorSyndrome); + PRINT_STRUCT_VALUE_LH (Struct, Type33, MemoryArrayErrorAddress); + PRINT_STRUCT_VALUE_LH (Struct, Type33, DeviceErrorAddress); + PRINT_STRUCT_VALUE_H (Struct, Type33, ErrorResolution); + break; + + // + // Management Device (Type 34) + // + case 34: + PRINT_PENDING_STRING (Struct, Type34, Description); + DisplayMDType (Struct->Type34->Type, Option); + PRINT_STRUCT_VALUE_H (Struct, Type34, Address); + DisplayMDAddressType (Struct->Type34->AddressType, Option); + break; + + // + // Management Device Component (Type 35) + // + case 35: + PRINT_PENDING_STRING (Struct, Type35, Description); + PRINT_STRUCT_VALUE_H (Struct, Type35, ManagementDeviceHandle); + PRINT_STRUCT_VALUE_H (Struct, Type35, ComponentHandle); + PRINT_STRUCT_VALUE_H (Struct, Type35, ThresholdHandle); + break; + + // + // Management Device Threshold Data (Type 36) + // + case 36: + PRINT_STRUCT_VALUE_H (Struct, Type36, LowerThresholdNonCritical); + PRINT_STRUCT_VALUE_H (Struct, Type36, UpperThresholdNonCritical); + PRINT_STRUCT_VALUE_H (Struct, Type36, LowerThresholdCritical); + PRINT_STRUCT_VALUE_H (Struct, Type36, UpperThresholdCritical); + PRINT_STRUCT_VALUE_H (Struct, Type36, LowerThresholdNonRecoverable); + PRINT_STRUCT_VALUE_H (Struct, Type36, UpperThresholdNonRecoverable); + break; + + // + // Memory Channel (Type 37) + // + case 37: + { + UINT8 Count; + MEMORY_DEVICE *Ptr; + DisplayMemoryChannelType (Struct->Type37->ChannelType, Option); + PRINT_STRUCT_VALUE_H (Struct, Type37, MaximumChannelLoad); + PRINT_STRUCT_VALUE_H (Struct, Type37, MemoryDeviceCount); + + Count = Struct->Type37->MemoryDeviceCount; + Ptr = Struct->Type37->MemoryDevice; + for (Index = 0; Index < Count; Index++) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_MEM_DEVICE), gShellDebug1HiiHandle, Index + 1); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_DEV_LOAD), gShellDebug1HiiHandle, Ptr[Index].DeviceLoad); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_DEV_HANDLE), gShellDebug1HiiHandle, Ptr[Index].DeviceHandle); + } + } + break; + + // + // IPMI Device Information (Type 38) + // + case 38: + DisplayIPMIDIBMCInterfaceType (Struct->Type38->InterfaceType, Option); + PRINT_STRUCT_VALUE_H (Struct, Type38, IPMISpecificationRevision); + PRINT_STRUCT_VALUE_H (Struct, Type38, I2CSlaveAddress); + PRINT_STRUCT_VALUE_H (Struct, Type38, NVStorageDeviceAddress); + PRINT_STRUCT_VALUE_LH (Struct, Type38, BaseAddress); + break; + + // + // System Power Supply (Type 39) + // + case 39: + PRINT_STRUCT_VALUE_H (Struct, Type39, PowerUnitGroup); + PRINT_PENDING_STRING (Struct, Type39, Location); + PRINT_PENDING_STRING (Struct, Type39, DeviceName); + PRINT_PENDING_STRING (Struct, Type39, Manufacturer); + PRINT_PENDING_STRING (Struct, Type39, SerialNumber); + PRINT_PENDING_STRING (Struct, Type39, AssetTagNumber); + PRINT_PENDING_STRING (Struct, Type39, ModelPartNumber); + PRINT_PENDING_STRING (Struct, Type39, RevisionLevel); + PRINT_STRUCT_VALUE_H (Struct, Type39, MaxPowerCapacity); + DisplaySPSCharacteristics ( + *(UINT16 *) &(Struct->Type39->PowerSupplyCharacteristics), + Option + ); + PRINT_STRUCT_VALUE_H (Struct, Type39, InputVoltageProbeHandle); + PRINT_STRUCT_VALUE_H (Struct, Type39, CoolingDeviceHandle); + PRINT_STRUCT_VALUE_H (Struct, Type39, InputCurrentProbeHandle); + break; + + // + // Additional Information (Type 40) + // + case 40: + { + UINT8 NumberOfEntries; + UINT8 EntryLength; + ADDITIONAL_INFORMATION_ENTRY *Entries; + + EntryLength = 0; + Entries = Struct->Type40->AdditionalInfoEntries; + NumberOfEntries = Struct->Type40->NumberOfAdditionalInformationEntries; + + PRINT_STRUCT_VALUE_H (Struct, Type40, NumberOfAdditionalInformationEntries); + + for (Index = 0; Index < NumberOfEntries; Index++) { + EntryLength = Entries->EntryLength; + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_ENTRYLEN), gShellDebug1HiiHandle, EntryLength); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_REFERENCEDHANDLE), gShellDebug1HiiHandle, Entries->ReferencedHandle); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_REFERENCEDOFFSET), gShellDebug1HiiHandle, Entries->ReferencedOffset); + PRINT_SMBIOS_STRING (Struct, Entries->EntryString, String); + PRINT_SMBIOS_BIT_FIELD (Struct, Entries->Value, Value, EntryLength - 5); + Entries = (ADDITIONAL_INFORMATION_ENTRY *) ((UINT8 *)Entries + EntryLength); + } + } + break; + + // + // Onboard Devices Extended Information (Type 41) + // + case 41: + PRINT_PENDING_STRING (Struct, Type41, ReferenceDesignation); + ShellPrintEx(-1,-1,(((Struct->Type41->DeviceType) & 0x80) != 0) ? L"Device Enabled\n": L"Device Disabled\n"); + DisplayOnboardDeviceTypes ((Struct->Type41->DeviceType) & 0x7F, Option); + PRINT_STRUCT_VALUE_H (Struct, Type41, DeviceTypeInstance); + PRINT_STRUCT_VALUE_H (Struct, Type41, SegmentGroupNum); + PRINT_STRUCT_VALUE_H (Struct, Type41, BusNum); + PRINT_STRUCT_VALUE_H (Struct, Type41, DevFuncNum); + break; + + // + // Management Controller Host Interface (Type 42) + // + case 42: + DisplayMCHostInterfaceType (Struct->Type42->InterfaceType, Option); + if (AE_SMBIOS_VERSION (0x3, 0x2)) { + PRINT_STRUCT_VALUE_H (Struct, Type42, InterfaceTypeSpecificDataLength); + PRINT_BIT_FIELD (Struct, Type42, InterfaceTypeSpecificData, Struct->Type42->InterfaceTypeSpecificDataLength); + } + break; + + // + // TPM Device (Type 43) + // + case 43: + PRINT_BIT_FIELD (Struct, Type43, VendorID, 4); + PRINT_STRUCT_VALUE_H (Struct, Type43, MajorSpecVersion); + PRINT_STRUCT_VALUE_H (Struct, Type43, MinorSpecVersion); + PRINT_STRUCT_VALUE_H (Struct, Type43, FirmwareVersion1); + PRINT_STRUCT_VALUE_H (Struct, Type43, FirmwareVersion2); + PRINT_PENDING_STRING (Struct, Type43, Description); + DisplayTpmDeviceCharacteristics (ReadUnaligned64 ((UINT64 *) (UINTN) &(Struct->Type43->Characteristics)), Option); + PRINT_STRUCT_VALUE_H (Struct, Type43, OemDefined); + break; + + // + // Processor Additional Information (Type 44) + // + case 44: + DisplayProcessorArchitectureType (Struct->Type44->ProcessorSpecificBlock.ProcessorArchType, Option); + break; + + // + // Inactive (Type 126) + // + case 126: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INACTIVE_STRUCT), gShellDebug1HiiHandle); + break; + + // + // End-of-Table (Type 127) + // + case 127: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_THIS_STRUCT_END_TABLE), gShellDebug1HiiHandle); + break; + + default: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_STRUCT_TYPE_UNDEFINED), gShellDebug1HiiHandle); + break; + } + + return EFI_SUCCESS; +} + +/** + Display BIOS Information (Type 0) information. + + @param[in] Chara The information bits. + @param[in] Option The optional information. +**/ +VOID +DisplayBiosCharacteristics ( + IN UINT64 Chara, + IN UINT8 Option + ) +{ + // + // Print header + // + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BIOS_CHAR), gShellDebug1HiiHandle); + // + // print option + // + PRINT_INFO_OPTION (Chara, Option); + + // + // Check all the bits and print information + // This function does not use Table because table of bits + // are designed not to deal with UINT64 + // + if (BIT (Chara, 0) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_RESERVED_BIT), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 1) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_RESERVED_BIT), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 2) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_UNKNOWN_BIT), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 3) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BIOS_CHAR_NOT_SUPPORTED), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 4) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ISA_SUPPORTED), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 5) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_MSA_SUPPORTED), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 6) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_EISA_SUPPORTED), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 7) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_PCI_SUPPORTED), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 8) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_PC_CARD_SUPPORTED), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 9) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_PLUG_PLAY_SUPPORTED), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 10) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_APM_SUPPORTED), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 11) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BIOS_UPGRADEABLE), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 12) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BIOS_SHADOWING), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 13) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_VESA_SUPPORTED), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 14) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ECSD_SUPPORT), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 15) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BOOT_FROM_CD_SUPPORTED), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 16) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_SELECTED_BOOT_SUPPORTED), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 17) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BIOS_ROM_SOCKETED), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 18) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BOOT_FROM_PC_CARD), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 19) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_EDD_ENHANCED_DRIVER), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 20) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_JAPANESE_FLOPPY_NEC), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 21) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_JAPANESE_FLOPPY_TOSHIBA), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 22) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_FLOPPY_SERVICES_SUPPORTED), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 23) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ONE_POINT_TWO_MB), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 24) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_720_KB), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 25) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_TWO_POINT_EIGHT_EIGHT_MB), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 26) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_PRINT_SCREEN_SUPPORT), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 27) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_KEYBOARD_SERV_SUPPORT), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 28) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_SERIAL_SERVICES_SUPPORT), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 29) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_PRINTER_SERVICES_SUPPORT), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 30) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_MONO_VIDEO_SUPPORT), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 31) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_NEC_PC_98), gShellDebug1HiiHandle); + } + // + // Just print the Reserved + // + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BITS_32_47), gShellDebug1HiiHandle); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BITS_48_64), gShellDebug1HiiHandle); +} + +/** + Display Bios Characteristice extensions1 information. + + @param[in] Byte1 The information. + @param[in] Option The optional information. +**/ +VOID +DisplayBiosCharacteristicsExt1 ( + IN UINT8 Byte1, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BIOS_CHAR_EXTENSION), gShellDebug1HiiHandle); + // + // Print option + // + PRINT_INFO_OPTION (Byte1, Option); + + // + // check bit and print + // + if (BIT (Byte1, 0) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ACPI_SUPPORTED), gShellDebug1HiiHandle); + } + + if (BIT (Byte1, 1) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_USB_LEGACY_SUPPORTED), gShellDebug1HiiHandle); + } + + if (BIT (Byte1, 2) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_AGP_SUPPORTED), gShellDebug1HiiHandle); + } + + if (BIT (Byte1, 3) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_I2O_BOOT_SUPPORTED), gShellDebug1HiiHandle); + } + + if (BIT (Byte1, 4) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_LS_120_BOOT_SUPPORTED), gShellDebug1HiiHandle); + } + + if (BIT (Byte1, 5) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ATAPI_ZIP_DRIVE), gShellDebug1HiiHandle); + } + + if (BIT (Byte1, 6) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_1394_BOOT_SUPPORTED), gShellDebug1HiiHandle); + } + + if (BIT (Byte1, 7) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_SMART_BATTERY_SUPPORTED), gShellDebug1HiiHandle); + } +} + +/** + Display Bios Characteristice extensions2 information. + + @param[in] byte2 The information. + @param[in] Option The optional information. +**/ +VOID +DisplayBiosCharacteristicsExt2 ( + IN UINT8 byte2, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BIOS_CHAR_EXTENSION_2), gShellDebug1HiiHandle); + // + // Print option + // + PRINT_INFO_OPTION (byte2, Option); + + if (BIT (byte2, 0) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BIOS_BOOT_SPEC_SUPP), gShellDebug1HiiHandle); + } + + if (BIT (byte2, 1) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_FUNCTION_KEY_INIT), gShellDebug1HiiHandle); + } + + if (AE_SMBIOS_VERSION (0x2, 0x4)) { + if (BIT (byte2, 2) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ENABLE_TAR_CONT_DIST), gShellDebug1HiiHandle); + } + if (AE_SMBIOS_VERSION (0x2, 0x7)) { + if (BIT (byte2, 3) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_UEFI_SPEC_SUPPORT), gShellDebug1HiiHandle); + } + if (BIT (byte2, 4) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_VIRTUAL_MACHINE), gShellDebug1HiiHandle); + } + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BITS_RSVD_FOR_FUTURE), gShellDebug1HiiHandle, 5); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BITS_RSVD_FOR_FUTURE), gShellDebug1HiiHandle, 3); + } + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BITS_RSVD_FOR_FUTURE), gShellDebug1HiiHandle, 2); + } +} + +/** + Display Processor Information (Type 4) information. + + @param[in] Family The family value. + @param[in] Option The option value. +**/ +VOID +DisplayProcessorFamily ( + UINT8 Family, + UINT8 Option + ) +{ + // + // Print prompt message + // + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_PROCESSOR_FAMILY), gShellDebug1HiiHandle); + // + // Print option + // + PRINT_INFO_OPTION (Family, Option); + + // + // Use switch to check + // + switch (Family) { + case 0x01: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_OTHER), gShellDebug1HiiHandle); + break; + + case 0x02: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_UNKNOWN), gShellDebug1HiiHandle); + break; + + case 0x03: + Print (L"8086\n"); + break; + + case 0x04: + Print (L"80286\n"); + break; + + case 0x05: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL386_PROCESSOR), gShellDebug1HiiHandle); + break; + + case 0x06: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL486_PROCESSOR), gShellDebug1HiiHandle); + break; + + case 0x07: + Print (L"8087\n"); + break; + + case 0x08: + Print (L"80287\n"); + break; + + case 0x09: + Print (L"80387\n"); + break; + + case 0x0A: + Print (L"80487\n"); + break; + + case 0x0B: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_PENTIUM_PROC_FAMILY), gShellDebug1HiiHandle); + break; + + case 0x0C: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_PENTIUM_PRO_PROC), gShellDebug1HiiHandle); + break; + + case 0x0D: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_PENTIUM_II_PROC), gShellDebug1HiiHandle); + break; + + case 0x0E: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_PENTIUM_PROC_MMX), gShellDebug1HiiHandle); + break; + + case 0x0F: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_CELERON_PROC), gShellDebug1HiiHandle); + break; + + case 0x10: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_PENTIUM_XEON_PROC), gShellDebug1HiiHandle); + break; + + case 0x11: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_PENTIUM_III_PROC), gShellDebug1HiiHandle); + break; + + case 0x12: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_M1_FAMILY), gShellDebug1HiiHandle); + break; + + case 0x13: + Print (L"M2 Family\n"); + break; + + case 0x14: + Print (L"Intel Celeron M\n"); + break; + + case 0x15: + Print (L"Intel Pentium 4 HT\n"); + break; + + case 0x18: + Print (L"AMD Duron\n"); + break; + + case 0x19: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_K5_FAMILY), gShellDebug1HiiHandle); + break; + + case 0x1A: + Print (L"K6 Family\n"); + break; + + case 0x1B: + Print (L"K6-2\n"); + break; + + case 0x1C: + Print (L"K6-3\n"); + break; + + case 0x1D: + Print (L"AMD Althon Processor Family\n"); + break; + + case 0x1E: + Print (L"AMD 29000 Family\n"); + break; + + case 0x1F: + Print (L"K6-2+\n"); + break; + + case 0x20: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_POWER_PC_FAMILY), gShellDebug1HiiHandle); + break; + + case 0x21: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_POWER_PC_601), gShellDebug1HiiHandle); + break; + + case 0x22: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_POWER_PC_603), gShellDebug1HiiHandle); + break; + + case 0x23: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_POWER_PC_603_PLUS), gShellDebug1HiiHandle); + break; + + case 0x24: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_POWER_PC_604), gShellDebug1HiiHandle); + break; + + case 0x25: + Print (L"Power PC 620\n"); + break; + + case 0x26: + Print (L"Power PC 704\n"); + break; + + case 0x27: + Print (L"Power PC 750\n"); + break; + + case 0x28: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_CORE_DUO), gShellDebug1HiiHandle); + break; + + case 0x29: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_CORE_DUO_MOBILE), gShellDebug1HiiHandle); + break; + + case 0x2A: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_CORE_SOLO_MOBILE), gShellDebug1HiiHandle); + break; + + case 0x2B: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_ATOM), gShellDebug1HiiHandle); + break; + + case 0x2C: + Print (L"Intel(R) Core(TM) M processor\n"); + break; + + case 0x2D: + Print (L"Intel(R) Core(TM) m3 processor\n"); + break; + + case 0x2E: + Print (L"Intel(R) Core(TM) m5 processor\n"); + break; + + case 0x2F: + Print (L"Intel(R) Core(TM) m7 processor\n"); + break; + + case 0x30: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ALPHA_FAMILY_2), gShellDebug1HiiHandle); + break; + + case 0x31: + Print (L"Alpha 21064\n"); + break; + + case 0x32: + Print (L"Alpha 21066\n"); + break; + + case 0x33: + Print (L"Alpha 21164\n"); + break; + + case 0x34: + Print (L"Alpha 21164PC\n"); + break; + + case 0x35: + Print (L"Alpha 21164a\n"); + break; + + case 0x36: + Print (L"Alpha 21264\n"); + break; + + case 0x37: + Print (L"Alpha 21364\n"); + break; + + case 0x38: + Print (L"AMD Turion II Ultra Dual-Core Mobile M Processor Family\n"); + break; + + case 0x39: + Print (L"AMD Turion II Dual-Core Mobile M Processor Family\n"); + break; + + case 0x3A: + Print (L"AMD Althon II Dual-Core M Processor Family\n"); + break; + + case 0x3B: + Print (L"AMD Opteron 6100 Series Processor\n"); + break; + + case 0x3C: + Print (L"AMD Opteron 4100 Series Processor\n"); + break; + + case 0x3D: + Print (L"AMD Opteron 6200 Series Processor\n"); + break; + + case 0x3E: + Print (L"AMD Opteron 4200 Series Processor\n"); + break; + + case 0x3F: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_AMD_FX_SERIES), gShellDebug1HiiHandle); + break; + + case 0x40: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_MIPS_FAMILY), gShellDebug1HiiHandle); + break; + + case 0x41: + Print (L"MIPS R4000\n"); + break; + + case 0x42: + Print (L"MIPS R4200\n"); + break; + + case 0x43: + Print (L"MIPS R4400\n"); + break; + + case 0x44: + Print (L"MIPS R4600\n"); + break; + + case 0x45: + Print (L"MIPS R10000\n"); + break; + + case 0x46: + Print (L"AMD C-Series Processor\n"); + break; + + case 0x47: + Print (L"AMD E-Series Processor\n"); + break; + + case 0x48: + Print (L"AMD A-Series Processor\n"); + break; + + case 0x49: + Print (L"AMD G-Series Processor\n"); + break; + + case 0x4A: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_AMD_Z_SERIES), gShellDebug1HiiHandle); + break; + + case 0x4B: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_AMD_R_SERIES), gShellDebug1HiiHandle); + break; + + case 0x4C: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_AMD_OPTERON_4300_SERIES), gShellDebug1HiiHandle); + break; + + case 0x4D: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_AMD_OPTERON_6300_SERIES), gShellDebug1HiiHandle); + break; + + case 0x4E: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_AMD_OPTERON_3300_SERIES), gShellDebug1HiiHandle); + break; + + case 0x4F: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_AMD_OPTERON_FIREPRO_SERIES), gShellDebug1HiiHandle); + break; + + case 0x50: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_SPARC_FAMILY), gShellDebug1HiiHandle); + break; + + case 0x51: + Print (L"SuperSparc\n"); + break; + + case 0x52: + Print (L"microSparc II\n"); + break; + + case 0x53: + Print (L"microSparc IIep\n"); + break; + + case 0x54: + Print (L"UltraSparc\n"); + break; + + case 0x55: + Print (L"UltraSparc II\n"); + break; + + case 0x56: + Print (L"UltraSparcIIi\n"); + break; + + case 0x57: + Print (L"UltraSparcIII\n"); + break; + + case 0x58: + Print (L"UltraSparcIIIi\n"); + break; + + case 0x60: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_68040_FAMILY), gShellDebug1HiiHandle); + break; + + case 0x61: + Print (L"68xx\n"); + break; + + case 0x62: + Print (L"68000\n"); + break; + + case 0x63: + Print (L"68010\n"); + break; + + case 0x64: + Print (L"68020\n"); + break; + + case 0x65: + Print (L"68030\n"); + break; + + case 0x66: + Print (L"AMD Athlon(TM) X4 Quad-Core Processor Family\n"); + break; + + case 0x67: + Print (L"AMD Opteron(TM) X1000 Series Processor\n"); + break; + + case 0x68: + Print (L"AMD Opteron(TM) X2000 Series APU\n"); + break; + + case 0x69: + Print (L"AMD Opteron(TM) A-Series Processor\n"); + break; + + case 0x6A: + Print (L"AMD Opteron(TM) X3000 Series APU\n"); + break; + + case 0x6B: + Print (L"AMD Zen Processor Family\n"); + break; + + case 0x70: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_HOBBIT_FAMILY), gShellDebug1HiiHandle); + break; + + case 0x78: + Print (L"Crusoe TM5000\n"); + break; + + case 0x79: + Print (L"Crusoe TM3000\n"); + break; + + case 0x7A: + Print (L"Efficeon TM8000\n"); + break; + + case 0x80: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_WEITEK), gShellDebug1HiiHandle); + break; + + case 0x82: + Print (L"Itanium\n"); + break; + + case 0x83: + Print (L"AMD Athlon64\n"); + break; + + case 0x84: + Print (L"AMD Opteron\n"); + break; + + case 0x85: + Print (L"AMD Sempron\n"); + break; + + case 0x86: + Print (L"AMD Turion64 Mobile\n"); + break; + + case 0x87: + Print (L"Dual-Core AMD Opteron\n"); + break; + + case 0x88: + Print (L"AMD Athlon 64X2 DualCore\n"); + break; + + case 0x89: + Print (L"AMD Turion 64X2 Mobile\n"); + break; + + case 0x8A: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_AMD_OPTERON_QUAD_CORE), gShellDebug1HiiHandle); + break; + + case 0x8B: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_AMD_OPTERON_THIRD_GENERATION), gShellDebug1HiiHandle); + break; + + case 0x8C: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_AMD_PHENOM_FX_QUAD_CORE), gShellDebug1HiiHandle); + break; + + case 0x8D: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_AMD_PHENOM_X4_QUAD_CORE), gShellDebug1HiiHandle); + break; + + case 0x8E: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_AMD_PHENOM_X2_DUAL_CORE), gShellDebug1HiiHandle); + break; + + case 0x8F: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_AMD_ATHLON_X2_DUAL_CORE), gShellDebug1HiiHandle); + break; + + case 0x90: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_PA_RISC_FAMILY), gShellDebug1HiiHandle); + break; + + case 0x91: + Print (L"PA-RISC 8500\n"); + break; + + case 0x92: + Print (L"PA-RISC 8000\n"); + break; + + case 0x93: + Print (L"PA-RISC 7300LC\n"); + break; + + case 0x94: + Print (L"PA-RISC 7200\n"); + break; + + case 0x95: + Print (L"PA-RISC 7100LC\n"); + break; + + case 0x96: + Print (L"PA-RISC 7100\n"); + break; + + case 0xA0: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_V30_FAMILY), gShellDebug1HiiHandle); + break; + + case 0xA1: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_3200_SERIES_QUAD_CORE), gShellDebug1HiiHandle); + break; + + case 0xA2: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_3000_SERIES_DUAL_CORE), gShellDebug1HiiHandle); + break; + + case 0xA3: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_5300_SERIES_QUAD_CORE), gShellDebug1HiiHandle); + break; + + case 0xA4: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_5100_SERIES_DUAL_CORE), gShellDebug1HiiHandle); + break; + + case 0xA5: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_5000_SERIES_DUAL_CORE), gShellDebug1HiiHandle); + break; + + case 0xA6: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_LV_DUAL_CORE), gShellDebug1HiiHandle); + break; + + case 0xA7: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_ULV_DUAL_CORE), gShellDebug1HiiHandle); + break; + + case 0xA8: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_7100_SERIES_DUAL_CORE), gShellDebug1HiiHandle); + break; + + case 0xA9: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_5400_SERIES_QUAD_CORE), gShellDebug1HiiHandle); + break; + + case 0xAA: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_QUAD_CORE), gShellDebug1HiiHandle); + break; + + case 0xAB: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_5200_SERIES_DUAL_CORE), gShellDebug1HiiHandle); + break; + + case 0xAC: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_7200_SERIES_DUAL_CORE), gShellDebug1HiiHandle); + break; + + case 0xAD: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_7300_SERIES_QUAD_CORE), gShellDebug1HiiHandle); + break; + + case 0xAE: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_7400_SERIES_QUAD_CORE), gShellDebug1HiiHandle); + break; + + case 0xAF: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_7400_SERIES_MULTI_CORE), gShellDebug1HiiHandle); + break; + + case 0xB0: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_PENTIUM_III_XEON), gShellDebug1HiiHandle); + break; + + case 0xB1: + Print (L"Pentium III Processorwith Intel SpeedStep Technology\n"); + break; + + case 0xB2: + Print (L"Pentium 4 processor\n"); + break; + + case 0xB3: + Print (L"Intel Xeon Processor\n"); + break; + + case 0xB4: + Print (L"AS400 Family\n"); + break; + + case 0xB5: + Print (L"Intel Xeon processor MP\n"); + break; + + case 0xB6: + Print (L"AMD Althon XP Processor Family\n"); + break; + + case 0xB7: + Print (L"AMD Althon MP Promcessor Family\n"); + break; + + case 0xB8: + Print (L"Intel Itanium 2 processor\n"); + break; + + case 0xB9: + Print (L"Intel Penium M processor\n"); + break; + + case 0xBA: + Print (L"Intel Celeron D processor\n"); + break; + + case 0xBB: + Print (L"Intel Pentium D processor\n"); + break; + + case 0xBC: + Print (L"Intel Pentium Processor Extreme Edition\n"); + break; + + case 0xBD: + Print (L"Intel Core Solo Processor\n"); + break; + + case 0xBF: + Print (L"Intel Core 2 Duo Processor\n"); + break; + + case 0xC0: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_CORE2_SOLO), gShellDebug1HiiHandle); + break; + + case 0xC1: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_CORE2_EXTREME), gShellDebug1HiiHandle); + break; + + case 0xC2: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_CORE2_QUAD), gShellDebug1HiiHandle); + break; + + case 0xC3: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_CORE2_EXTREME), gShellDebug1HiiHandle); + break; + + case 0xC4: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_CORE2_DUO_MOBILE), gShellDebug1HiiHandle); + break; + + case 0xC5: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_CORE2_SOLO_MOBILE), gShellDebug1HiiHandle); + break; + + case 0xC6: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_CORE_I7), gShellDebug1HiiHandle); + break; + + case 0xC7: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_CELERON_DUAL_CORE), gShellDebug1HiiHandle); + break; + + case 0xC8: + Print (L"IBM 390\n"); + break; + + case 0xC9: + Print (L"G4\n"); + break; + + case 0xCA: + Print (L"G5\n"); + break; + + case 0xCB: + Print (L"G6\n"); + break; + + case 0xCC: + Print (L"zArchitecture\n"); + break; + + case 0xCD: + Print (L"Intel Core i5 processor\n"); + break; + + case 0xCE: + Print (L"Intel Core i3 processor\n"); + break; + + case 0xCF: + Print (L"Intel Core i9 processor\n"); + break; + + case 0xD2: + Print (L"ViaC7M\n"); + break; + + case 0xD3: + Print (L"ViaC7D\n"); + break; + + case 0xD4: + Print (L"ViaC7\n"); + break; + + case 0xD5: + Print (L"Eden\n"); + break; + + case 0xD6: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_MULTI_CORE), gShellDebug1HiiHandle); + break; + + case 0xD7: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_3_SERIES_DUAL_CORE), gShellDebug1HiiHandle); + break; + + case 0xD8: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_3_SERIES_QUAD_CORE), gShellDebug1HiiHandle); + break; + + case 0xDA: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_5_SERIES_DUAL_CORE), gShellDebug1HiiHandle); + break; + + case 0xDB: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_5_SERIES_QUAD_CORE), gShellDebug1HiiHandle); + break; + + case 0xDD: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_7_SERIES_DUAL_CORE), gShellDebug1HiiHandle); + break; + + case 0xDE: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_7_SERIES_QUAD_CORE), gShellDebug1HiiHandle); + break; + + case 0xDF: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_7_SERIES_MULTI_CORE), gShellDebug1HiiHandle); + break; + + case 0xE0: + Print (L"Multi-Core Intel Xeon processor 3400 Series\n"); + break; + + case 0xE4: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_AMD_OPTERON_3000_SERIES), gShellDebug1HiiHandle); + break; + + case 0xE5: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_AMD_SEMPRON_II), gShellDebug1HiiHandle); + break; + + + case 0xE6: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_AMD_EMBEDDED_OPTERON_QUAD_CORE), gShellDebug1HiiHandle); + break; + + case 0xE7: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_AMD_PHENOM_TRIPLE_CORE), gShellDebug1HiiHandle); + break; + + case 0xE8: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_AMD_TURION_ULTRA_DUAL_CORE_MOBILE), gShellDebug1HiiHandle); + break; + + case 0xE9: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_AMD_TURION_DUAL_CORE_MOBILE), gShellDebug1HiiHandle); + break; + + case 0xEA: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_AMD_ATHLON_DUAL_CORE), gShellDebug1HiiHandle); + break; + + case 0xEB: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_AMD_SEMPRON_SI), gShellDebug1HiiHandle); + break; + + case 0xEC: + Print (L"AMD Phenom II Processor Family\n"); + break; + + case 0xED: + Print (L"AMD Althon II Processor Family\n"); + break; + + case 0xEE: + Print (L"Six-Core AMD Opteron Processor Family\n"); + break; + + case 0xEF: + Print (L"AMD Sempron M Processor Family\n"); + break; + + case 0xFA: + Print (L"i860\n"); + break; + + case 0xFB: + Print (L"i960\n"); + break; + + default: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_UNDEFINED_PROC_FAMILY), gShellDebug1HiiHandle); + } + // + // end switch + // +} + +/** + Display processor family information. + + @param[in] Family2 The family value. + @param[in] Option The option value. +**/ +VOID +DisplayProcessorFamily2 ( + IN UINT16 Family2, + IN UINT8 Option + ) +{ + // + // Print prompt message + // + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_PROCESSOR_FAMILY), gShellDebug1HiiHandle); + + // + // Print option + // + PRINT_INFO_OPTION (Family2, Option); + + // + // Use switch to check + // + switch (Family2) { + case 0x100: + Print (L"ARMv7\n"); + break; + + case 0x101: + Print (L"ARMv8\n"); + break; + + case 0x104: + Print (L"SH-3\n"); + break; + + case 0x105: + Print (L"SH-4\n"); + break; + + case 0x118: + Print (L"ARM\n"); + break; + + case 0x119: + Print (L"StrongARM\n"); + break; + + case 0x12C: + Print (L"6x86\n"); + break; + + case 0x12D: + Print (L"MediaGX\n"); + break; + + case 0x12E: + Print (L"MII\n"); + break; + + case 0x140: + Print (L"WinChip\n"); + break; + + case 0x15E: + Print (L"DSP\n"); + break; + + case 0x1F4: + Print (L"Video Processor\n"); + break; + + case 0x200: + Print (L"RISC-V RV32\n"); + break; + + case 0x201: + Print (L"RISC-V RV64\n"); + break; + + case 0x202: + Print (L"RISC-V RV128\n"); + break; + + default: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_UNDEFINED_PROC_FAMILY), gShellDebug1HiiHandle); + } + +} + +/** + Display processor voltage information. + + @param[in] Voltage The Voltage. + Bit 7 Set to 0, indicating 'legacy' mode for processor voltage + Bits 6:4 Reserved, must be zero + Bits 3:0 Voltage Capability. + A Set bit indicates that the voltage is supported. + Bit 0 - 5V + Bit 1 - 3.3V + Bit 2 - 2.9V + Bit 3 - Reserved, must be zero. + + Note: + Setting of multiple bits indicates the socket is configurable + If bit 7 is set to 1, the remaining seven bits of the field are set to + contain the processor's current voltage times 10. + For example, the field value for a processor voltage of 1.8 volts would be + 92h = 80h + (1.8 * 10) = 80h + 18 = 80h +12h. + + @param[in] Option The option. +**/ +VOID +DisplayProcessorVoltage ( + IN UINT8 Voltage, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_PROC_INFO), gShellDebug1HiiHandle); + // + // Print option + // + PRINT_INFO_OPTION (Voltage, Option); + + if (BIT (Voltage, 7) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_PROC_CURRENT_VOLTAGE), gShellDebug1HiiHandle, (Voltage - 0x80)); + } else { + if (BIT (Voltage, 0) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_5V_SUPOPRTED), gShellDebug1HiiHandle); + } + + if (BIT (Voltage, 1) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_33V_SUPPORTED), gShellDebug1HiiHandle); + } + + if (BIT (Voltage, 2) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_29V_SUPPORTED), gShellDebug1HiiHandle); + } + // + // check the reserved zero bits: + // + if (BIT (Voltage, 3) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BIT3_NOT_ZERO), gShellDebug1HiiHandle); + } + + if (BIT (Voltage, 4) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BIT4_NOT_ZERO), gShellDebug1HiiHandle); + } + + if (BIT (Voltage, 5) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BIT5_NOT_ZERO), gShellDebug1HiiHandle); + } + + if (BIT (Voltage, 6) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BIT6_NOT_ZERO), gShellDebug1HiiHandle); + } + } +} + +/** + Display processor information. + + @param[in] Status The status. +Bit 7 Reserved, must be 0 +Bit 6 CPU Socket Populated + 1 - CPU Socket Populated + 0 - CPU Socket Unpopulated +Bits 5:3 Reserved, must be zero +Bits 2:0 CPU Status + 0h - Unknown + 1h - CPU Enabled + 2h - CPU Disabled by User via BIOS Setup + 3h - CPU Disabled By BIOS (POST Error) + 4h - CPU is Idle, waiting to be enabled. + 5-6h - Reserved + 7h - Other + + @param[in] Option The option +**/ +VOID +DisplayProcessorStatus ( + IN UINT8 Status, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_PROC_STATUS), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Status, Option); + + if (BIT (Status, 7) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BIT7_NOT_ZERO), gShellDebug1HiiHandle); + } else if (BIT (Status, 5) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BIT5_NOT_ZERO), gShellDebug1HiiHandle); + } else if (BIT (Status, 4) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BIT4_NOT_ZERO), gShellDebug1HiiHandle); + } else if (BIT (Status, 3) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BIT3_NOT_ZERO), gShellDebug1HiiHandle); + } + // + // Check BIT 6 + // + if (BIT (Status, 6) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_CPU_SOCKET_POPULATED), gShellDebug1HiiHandle); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_CPU_SOCKET_UNPOPULATED), gShellDebug1HiiHandle); + } + // + // Check BITs 2:0 + // + switch (Status & 0x07) { + case 0: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_UNKNOWN), gShellDebug1HiiHandle); + break; + + case 1: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_CPU_ENABLED), gShellDebug1HiiHandle); + break; + + case 2: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_CPU_DISABLED_BY_USER), gShellDebug1HiiHandle); + break; + + case 3: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_CPU_DIABLED_BY_BIOS), gShellDebug1HiiHandle); + break; + + case 4: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_CPU_IDLE), gShellDebug1HiiHandle); + break; + + case 7: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_OTHERS), gShellDebug1HiiHandle); + break; + + default: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_RESERVED), gShellDebug1HiiHandle); + } +} + +/** + Display information about Memory Controller Information (Type 5). + + @param[in] Size Memory size. + @param[in] SlotNum Which slot is this about. + @param[in] Option Option for the level of detail output required. +**/ +VOID +DisplayMaxMemoryModuleSize ( + IN UINT8 Size, + IN UINT8 SlotNum, + IN UINT8 Option + ) +{ + UINTN MaxSize; + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_SIZE_LARGEST_MEM), gShellDebug1HiiHandle); + // + // MaxSize is determined by follow formula + // + MaxSize = (UINTN) 1 << Size; + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ONE_VAR_MB), gShellDebug1HiiHandle, MaxSize); + + if (Option >= SHOW_DETAIL) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_MAX_AMOUNT_MEM), gShellDebug1HiiHandle); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ONE_VAR_MB), gShellDebug1HiiHandle, MaxSize, SlotNum, MaxSize * SlotNum); + } +} + +/** + Display information about memory configuration handles. + + @param[in] Handles The buffer of handles to output info on. + @param[in] SlotNum The number of handles in the above buffer. + @param[in] Option Option for the level of detail output required. +**/ +VOID +DisplayMemoryModuleConfigHandles ( + IN UINT16 *Handles, + IN UINT8 SlotNum, + IN UINT8 Option + ) +{ + UINT8 Index; + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_HANDLES_CONTROLLED), gShellDebug1HiiHandle, SlotNum); + + if (Option >= SHOW_DETAIL) { + // + // No handle, Handles is INVALID. + // + if (SlotNum == 0) { + return ; + } + + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_HANDLES_LIST_CONTROLLED), gShellDebug1HiiHandle); + for (Index = 0; Index < SlotNum; Index++) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_HANDLE), gShellDebug1HiiHandle, Index + 1, Handles[Index]); + } + } +} + +/** + Display Memory Module Information (Type 6). + + @param[in] BankConnections + @param[in] Option +**/ +VOID +DisplayMmBankConnections ( + IN UINT8 BankConnections, + IN UINT8 Option + ) +{ + UINT8 High; + UINT8 Low; + + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BANK_CONNECTIONS), gShellDebug1HiiHandle); + // + // Print option + // + PRINT_INFO_OPTION (BankConnections, Option); + + // + // Divide it to high and low + // + High = (UINT8) (BankConnections & 0xF0); + Low = (UINT8) (BankConnections & 0x0F); + if (High != 0xF) { + if (Low != 0xF) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BANK_RAS), gShellDebug1HiiHandle, High, Low, High, Low); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BANK_RAS_2), gShellDebug1HiiHandle, High, High); + } + } else { + if (Low != 0xF) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BANK_RAS_2), gShellDebug1HiiHandle, Low, Low); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_NO_BANKS_CONNECTED), gShellDebug1HiiHandle); + } + } +} + +/** + Display memory informcation. + + Bits 0:6 Size (n), + where 2**n is the size in MB with three special-case values: + 7Dh Not determinable (Installed Size only) + 7Eh Module is installed, but no memory has been enabled + 7Fh Not installed + Bit 7 Defines whether the memory module has a single- (0) + or double-bank (1) connection. + + @param[in] Size - The size + @param[in] Option - The option +**/ +VOID +DisplayMmMemorySize ( + IN UINT8 Size, + IN UINT8 Option + ) +{ + UINT8 Value; + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_MEMORY_SIZE), gShellDebug1HiiHandle); + // + // Print option + // + PRINT_INFO_OPTION (Size, Option); + + // + // Get the low bits(0-6 bit) + // + Value = (UINT8) (Size & 0x7F); + if (Value == 0x7D) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_MEM_SIZE_NOT_DETERMINABLE), gShellDebug1HiiHandle); + } else if (Value == 0x7E) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_MODULE_INSTALLED), gShellDebug1HiiHandle); + } else if (Value == 0x7F) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_NOT_INSTALLED), gShellDebug1HiiHandle); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_MEM_SIZE), gShellDebug1HiiHandle, 1 << Value); + } + + if (BIT (Size, 7) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_MEM_MODULE_DOUBLE_BANK), gShellDebug1HiiHandle); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_MEM_MODULE_SINGLE_BANK), gShellDebug1HiiHandle); + } +} + +/** + Display Cache Configuration. + + @param[in] CacheConfiguration Cache Configuration. +Bits 15:10 Reserved, must be 0 +Bits 9:8 Operational Mode + 0h - Write Through + 1h - Write Back + 2h - Varies with Memory Address + 3h - Unknown +Bit 7 Enabled/Disabled + 1 - Enabled + 0 - Disabled +Bits 6:5 Location + 0h - Internal + 1h - External + 2h - Reserved + 3h - Unknown +Bit 4 Reserved, must be zero +Bit 3 Cache Socketed + 1 - Socketed + 0 - Unsocketed +Bits 2:0 Cache Level + 1 through 8 (For example, an L1 cache would + use value 000b and an L3 cache would use 010b.) + + @param[in] Option The option +**/ +VOID +DisplayCacheConfiguration ( + IN UINT16 CacheConfiguration, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_CACHE_CONFIGURATION), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (CacheConfiguration, Option); + + if (BIT (CacheConfiguration, 15) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BIT15_NOT_ZERO), gShellDebug1HiiHandle); + } else if (BIT (CacheConfiguration, 14) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BIT14_NOT_ZERO), gShellDebug1HiiHandle); + } else if (BIT (CacheConfiguration, 13) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BIT13_NOT_ZERO), gShellDebug1HiiHandle); + } else if (BIT (CacheConfiguration, 12) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BIT12_NOT_ZERO), gShellDebug1HiiHandle); + } else if (BIT (CacheConfiguration, 11) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BIT11_NOT_ZERO), gShellDebug1HiiHandle); + } else if (BIT (CacheConfiguration, 10) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BIT10_NOT_ZERO), gShellDebug1HiiHandle); + } else if (BIT (CacheConfiguration, 4) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BIT4_NOT_ZERO), gShellDebug1HiiHandle); + } + + // + // Check BITs 9:8 + // + switch ((CacheConfiguration & 0x300) >> 8) { + case 0: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_CACHE_WRITE_THROUGH), gShellDebug1HiiHandle); + break; + + case 1: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_CACHE_WRITE_BACK), gShellDebug1HiiHandle); + break; + + case 2: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_CACHE_VARIES_WITH_MEM_ADDR), gShellDebug1HiiHandle); + break; + + case 3: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_UNKNOWN), gShellDebug1HiiHandle); + break; + } + + // + // Check BIT 7 + // + if (BIT (CacheConfiguration, 7) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ENABLED), gShellDebug1HiiHandle); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_DISABLED), gShellDebug1HiiHandle); + } + + // + // Check BITs 6:5 + // + switch ((CacheConfiguration & 0x60) >> 5) { + case 0: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_CACHE_INTERNAL), gShellDebug1HiiHandle); + break; + + case 1: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_CACHE_EXTERNAL), gShellDebug1HiiHandle); + break; + + case 2: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_RESERVED), gShellDebug1HiiHandle); + break; + + case 3: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_UNKNOWN), gShellDebug1HiiHandle); + break; + } + + // + // Check BIT 3 + // + if (BIT (CacheConfiguration, 3) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_CACHE_SOCKETED), gShellDebug1HiiHandle); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_CACHE_NOT_SOCKETED), gShellDebug1HiiHandle); + } + + + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_CACHE_LEVEL), gShellDebug1HiiHandle, (CacheConfiguration & 0x07) + 1); +} + +/** + The Slot ID field of the System Slot structure provides a mechanism to + correlate the physical attributes of the slot to its logical access method + (which varies based on the Slot Type field). + + @param[in] SlotId - The slot ID + @param[in] SlotType - The slot type + @param[in] Option - The Option +**/ +VOID +DisplaySystemSlotId ( + IN UINT16 SlotId, + IN UINT8 SlotType, + IN UINT8 Option + ) +{ + // + // Display slot type first + // + DisplaySystemSlotType (SlotType, Option); + + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_SLOT_ID), gShellDebug1HiiHandle); + // + // print option + // + PRINT_INFO_OPTION (SlotType, Option); + + switch (SlotType) { + // + // Slot Type: MCA + // + case 0x04: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_LOGICAL_MICRO_CHAN), gShellDebug1HiiHandle); + if (SlotId > 0 && SlotId < 15) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ONE_VAR_D), gShellDebug1HiiHandle, SlotId); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ERROR_NOT_1_15), gShellDebug1HiiHandle); + } + break; + + // + // EISA + // + case 0x05: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_LOGICAL_EISA_NUM), gShellDebug1HiiHandle); + if (SlotId > 0 && SlotId < 15) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ONE_VAR_D), gShellDebug1HiiHandle, SlotId); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ERROR_NOT_1_15), gShellDebug1HiiHandle); + } + break; + + // + // Slot Type: PCI + // + case 0x06: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_VALUE_PRESENT), gShellDebug1HiiHandle, SlotId); + break; + + // + // PCMCIA + // + case 0x07: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_IDENTIFIES_ADAPTER_NUM), gShellDebug1HiiHandle, SlotId); + break; + + // + // Slot Type: PCI-E + // + case 0xA5: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_VALUE_PRESENT), gShellDebug1HiiHandle, SlotId); + break; + + default: + if ((SlotType >= 0x0E && SlotType <= 0x12) || (SlotType >= 0xA6 && SlotType <= 0xB6)){ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_VALUE_PRESENT), gShellDebug1HiiHandle, SlotId); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_UNDEFINED_SLOT_ID), gShellDebug1HiiHandle); + } + } +} + +/** + Display System Boot Information (Type 32) information. + + @param[in] Parameter The parameter. + @param[in] Option The options. +**/ +VOID +DisplaySystemBootStatus ( + IN UINT8 Parameter, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_SYSTEM_BOOT_STATUS), gShellDebug1HiiHandle); + // + // Print option + // + PRINT_INFO_OPTION (Parameter, Option); + + // + // Check value and print + // + if (Parameter == 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_NO_ERRORS_DETECTED), gShellDebug1HiiHandle); + } else if (Parameter == 1) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_NO_BOOTABLE_MEDIA), gShellDebug1HiiHandle); + } else if (Parameter == 2) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_NORMAL_OP_SYSTEM), gShellDebug1HiiHandle); + } else if (Parameter == 3) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_FIRMWARE_DETECTED), gShellDebug1HiiHandle); + } else if (Parameter == 4) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_OP_SYSTEM), gShellDebug1HiiHandle); + } else if (Parameter == 5) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_USER_REQUESTED_BOOT), gShellDebug1HiiHandle); + } else if (Parameter == 6) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_SYSTEM_SECURITY_VIOLATION), gShellDebug1HiiHandle); + } else if (Parameter == 7) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_PREV_REQ_IMAGE), gShellDebug1HiiHandle); + } else if (Parameter == 8) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_WATCHDOG_TIMER), gShellDebug1HiiHandle); + } else if (Parameter >= 9 && Parameter <= 127) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_RSVD_FUTURE_ASSIGNMENT), gShellDebug1HiiHandle); + } else if (Parameter >= 128 && Parameter <= 191) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_VENDOR_OEM_SPECIFIC), gShellDebug1HiiHandle); + } else if (Parameter >= 192) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_PRODUCT_SPEC_IMPLMENTATION), gShellDebug1HiiHandle); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ERROR_VALUE), gShellDebug1HiiHandle); + } +} + +/** + Display Portable Battery (Type 22) information. + + The date the cell pack was manufactured, in packed format: + Bits 15:9 Year, biased by 1980, in the range 0 to 127. + Bits 8:5 Month, in the range 1 to 12. + Bits 4:0 Date, in the range 1 to 31. + For example, 01 February 2000 would be identified as + 0010 1000 0100 0001b (0x2841). + + @param[in] Date The date + @param[in] Option The option +**/ +VOID +DisplaySBDSManufactureDate ( + IN UINT16 Date, + IN UINT8 Option + ) +{ + UINTN Day; + UINTN Month; + UINTN Year; + + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_SBDS_MANUFACTURE_DATE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Date, Option); + // + // Print date + // + Day = Date & 0x001F; + Month = (Date & 0x01E0) >> 5; + Year = ((Date & 0xFE00) >> 9) + 1980; + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_MONTH_DAY_YEAR), gShellDebug1HiiHandle, Day, Month, Year); + +} + +/** + Display System Reset (Type 23) information. + + +Identifies the system-reset capabilities for the system. + Bits 7:6 Reserved for future assignment via this specification, set to 00b. + Bit 5 System contains a watchdog timer, either True (1) or False (0). + Bits 4:3 Boot Option on Limit. + Identifies the system action to be taken when the Reset Limit is reached, one of: + 00b Reserved, do not use. + 01b Operating system + 10b System utilities + 11b Do not rebootBits + 2:1 Boot Option. Indicates the action to be taken following a watchdog reset, one of: + 00b Reserved, do not use. + 01b Operating system + 10b System utilities + 11b Do not reboot + Bit 0 Status. + 1b The system reset is enabled by the user + 0b The system reset is not enabled by the user + + @param[in] Reset Reset + @param[in] Option The option +**/ +VOID +DisplaySystemResetCapabilities ( + IN UINT8 Reset, + IN UINT8 Option + ) +{ + UINTN Temp; + + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_SYSTEM_RESET_CAPABILITIES), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Reset, Option); + + // + // Check reserved bits 7:6 + // + if ((Reset & 0xC0) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BITS_RESERVED_ZERO), gShellDebug1HiiHandle); + } + // + // Watch dog + // + if (BIT (Reset, 5) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_WATCHDOG_TIMER_2), gShellDebug1HiiHandle); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_SYSTEM_NOT_CONTAIN_TIMER), gShellDebug1HiiHandle); + } + // + // Boot Option on Limit + // + Temp = (Reset & 0x18) >> 3; + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BOOT_OPTION_LIMIT), gShellDebug1HiiHandle); + switch (Temp) { + case 0: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_RESERVED), gShellDebug1HiiHandle); + break; + + case 1: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_OP_SYSTEM_2), gShellDebug1HiiHandle); + break; + + case 2: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_SYSTEM_UTIL), gShellDebug1HiiHandle); + break; + + case 3: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_DO_NOT_REBOOT), gShellDebug1HiiHandle); + break; + } + // + // Boot Option + // + Temp = (Reset & 0x06) >> 1; + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BOOT_OPTION), gShellDebug1HiiHandle); + switch (Temp) { + case 0: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_RESERVED), gShellDebug1HiiHandle); + break; + + case 1: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_OP_SYSTEM_2), gShellDebug1HiiHandle); + break; + + case 2: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_SYSTEM_UTIL), gShellDebug1HiiHandle); + break; + + case 3: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_DO_NOT_REBOOT), gShellDebug1HiiHandle); + break; + } + // + // Reset enable flag + // + if ((Reset & 0x01) != 0) { + Print (L"The system reset is enabled by the user\n"); + } else { + Print (L"The system reset is disabled by the user\n"); + } +} + +/** + Display Hardware Security (Type 24) information. + + +Identifies the password and reset status for the system: + +Bits 7:6 Power-on Password Status, one of: + 00b Disabled + 01b Enabled + 10b Not Implemented + 11b Unknown +Bits 5:4 Keyboard Password Status, one of: + 00b Disabled + 01b Enabled + 10b Not Implemented + 11b Unknown +Bits 3:2 Administrator Password Status, one of: + 00b Disabled + 01b Enabled + 10b Not Implemented + 11b Unknown +Bits 1:0 Front Panel Reset Status, one of: + 00b Disabled + 01b Enabled + 10b Not Implemented + 11b Unknown + + @param[in] Settings The device settings. + @param[in] Option The device options. +**/ +VOID +DisplayHardwareSecuritySettings ( + IN UINT8 Settings, + IN UINT8 Option + ) +{ + UINTN Temp; + + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_HARDWARE_SECURITY_SET), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Settings, Option); + + // + // Power-on Password Status + // + Temp = (Settings & 0xC0) >> 6; + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_POWER_ON_PASSWORD), gShellDebug1HiiHandle); + switch (Temp) { + case 0: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_DISABLED), gShellDebug1HiiHandle); + break; + + case 1: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ENABLED_NEWLINE), gShellDebug1HiiHandle); + break; + + case 2: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_NOT_IMPLEMENTED), gShellDebug1HiiHandle); + break; + + case 3: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_UNKNOWN), gShellDebug1HiiHandle); + break; + } + // + // Keyboard Password Status + // + Temp = (Settings & 0x30) >> 4; + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_KEYBOARD_PASSWORD), gShellDebug1HiiHandle); + switch (Temp) { + case 0: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_DISABLED), gShellDebug1HiiHandle); + break; + + case 1: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ENABLED_NEWLINE), gShellDebug1HiiHandle); + break; + + case 2: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_NOT_IMPLEMENTED), gShellDebug1HiiHandle); + break; + + case 3: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_UNKNOWN), gShellDebug1HiiHandle); + break; + } + // + // Administrator Password Status + // + Temp = (Settings & 0x0C) >> 2; + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ADMIN_PASSWORD_STATUS), gShellDebug1HiiHandle); + switch (Temp) { + case 0: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_DISABLED), gShellDebug1HiiHandle); + break; + + case 1: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ENABLED_NEWLINE), gShellDebug1HiiHandle); + break; + + case 2: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_NOT_IMPLEMENTED), gShellDebug1HiiHandle); + break; + + case 3: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_UNKNOWN), gShellDebug1HiiHandle); + break; + } + // + // Front Panel Reset Status + // + Temp = Settings & 0x3; + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_FRONT_PANEL_RESET), gShellDebug1HiiHandle); + switch (Temp) { + case 0: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_DISABLED), gShellDebug1HiiHandle); + break; + + case 1: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_ENABLED_NEWLINE), gShellDebug1HiiHandle); + break; + + case 2: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_NOT_IMPLEMENTED), gShellDebug1HiiHandle); + break; + + case 3: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_UNKNOWN), gShellDebug1HiiHandle); + break; + } +} + +/** + Display Out-of-Band Remote Access (Type 30) information. + + @param[in] Connections The device characteristics. + @param[in] Option The device options. +**/ +VOID +DisplayOBRAConnections ( + IN UINT8 Connections, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_CONNECTIONS), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Connections, Option); + + // + // Check reserved bits 7:2 + // + if ((Connections & 0xFC) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BITS_RESERVED_ZERO_2), gShellDebug1HiiHandle); + } + // + // Outbound Connection + // + if (BIT (Connections, 1) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_OUTBOUND_CONN_ENABLED), gShellDebug1HiiHandle); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_OTUBOUND_CONN_DISABLED), gShellDebug1HiiHandle); + } + // + // Inbound Connection + // + if (BIT (Connections, 0) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INBOIUND_CONN_ENABLED), gShellDebug1HiiHandle); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INBOUND_CONN_DISABLED), gShellDebug1HiiHandle); + } +} + +/** + Display System Power Supply (Type 39) information. + + @param[in] Characteristics The device characteristics. + @param[in] Option The device options. +**/ +VOID +DisplaySPSCharacteristics ( + IN UINT16 Characteristics, + IN UINT8 Option + ) +{ + UINTN Temp; + + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_POWER_SUPPLY_CHAR), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Characteristics, Option); + + // + // Check reserved bits 15:14 + // + if ((Characteristics & 0xC000) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BITS_15_14_RSVD), gShellDebug1HiiHandle); + } + // + // Bits 13:10 - DMTF Power Supply Type + // + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_TYPE), gShellDebug1HiiHandle); + Temp = (Characteristics & 0x1C00) >> 10; + switch (Temp) { + case 1: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_OTHER_SPACE), gShellDebug1HiiHandle); + break; + + case 2: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_UNKNOWN), gShellDebug1HiiHandle); + break; + + case 3: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_LINEAR), gShellDebug1HiiHandle); + break; + + case 4: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_SWITCHING), gShellDebug1HiiHandle); + break; + + case 5: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BATTERY), gShellDebug1HiiHandle); + break; + + case 6: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_UPS), gShellDebug1HiiHandle); + break; + + case 7: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_CONVERTER), gShellDebug1HiiHandle); + break; + + case 8: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_REGULATOR), gShellDebug1HiiHandle); + break; + + default: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_RESERVED_2), gShellDebug1HiiHandle); + } + // + // Bits 9:7 - Status + // + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_STATUS_DASH), gShellDebug1HiiHandle); + Temp = (Characteristics & 0x380) >> 7; + switch (Temp) { + case 1: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_OTHER_SPACE), gShellDebug1HiiHandle); + break; + + case 2: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_UNKNOWN), gShellDebug1HiiHandle); + break; + + case 3: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_OK), gShellDebug1HiiHandle); + break; + + case 4: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_NON_CRITICAL), gShellDebug1HiiHandle); + break; + + case 5: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_CRITICAL_POWER_SUPPLY), gShellDebug1HiiHandle); + break; + + default: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_UNDEFINED), gShellDebug1HiiHandle); + } + // + // Bits 6:3 - DMTF Input Voltage Range Switching + // + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_INPUT_VOLTAGE_RANGE), gShellDebug1HiiHandle); + Temp = (Characteristics & 0x78) >> 3; + switch (Temp) { + case 1: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_OTHER_SPACE), gShellDebug1HiiHandle); + break; + + case 2: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_UNKNOWN), gShellDebug1HiiHandle); + break; + + case 3: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_MANUAL), gShellDebug1HiiHandle); + break; + + case 4: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_AUTO_SWITCH), gShellDebug1HiiHandle); + break; + + case 5: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_WIDE_RANGE), gShellDebug1HiiHandle); + break; + + case 6: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_NOT_APPLICABLE), gShellDebug1HiiHandle); + break; + + default: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_RESERVED_3), gShellDebug1HiiHandle); + break; + } + // + // Power supply is unplugged from the wall + // + if (BIT (Characteristics, 2) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_POWER_SUPPLY_UNPLUGGED), gShellDebug1HiiHandle); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_POWER_SUPPLY_PLUGGED), gShellDebug1HiiHandle); + } + // + // Power supply is present + // + if (BIT (Characteristics, 1) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_POWER_SUPPLY_PRESENT), gShellDebug1HiiHandle); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_POWER_SUPPLY_NOT_PRESENT), gShellDebug1HiiHandle); + } + // + // hot replaceable + // + if (BIT (Characteristics, 0) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_POWER_SUPPLY_REPLACE), gShellDebug1HiiHandle); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_POWER_SUPPLY_NOT_REPLACE), gShellDebug1HiiHandle); + } +} + +/** + Display TPM Device (Type 43) Characteristics. + + @param[in] Chara The information bits. + @param[in] Option The optional information. +**/ +VOID +DisplayTpmDeviceCharacteristics ( + IN UINT64 Chara, + IN UINT8 Option + ) +{ + // + // Print header + // + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_TPM_DEVICE_CHAR), gShellDebug1HiiHandle); + // + // print option + // + PRINT_INFO_OPTION (Chara, Option); + + // + // Check all the bits and print information + // This function does not use Table because table of bits + // are designed not to deal with UINT64 + // + if (BIT (Chara, 0) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_RESERVED_BIT), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 1) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_RESERVED_BIT), gShellDebug1HiiHandle); + } + if (BIT (Chara, 2) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_TPM_DEVICE_CHAR_NOT_SUPPORTED), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 3) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_TPM_DEVICE_CONFIG_FWU), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 4) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_TPM_DEVICE_CONFIG_PLAT_SW), gShellDebug1HiiHandle); + } + + if (BIT (Chara, 5) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_TPM_DEVICE_CONFIG_OEM), gShellDebug1HiiHandle); + } + + // + // Just print the Reserved + // + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_PRINTINFO_BITS_06_63), gShellDebug1HiiHandle); + +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/PrintInfo.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/PrintInfo.h new file mode 100644 index 00000000..021139d4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/PrintInfo.h @@ -0,0 +1,441 @@ +/** @file + Module to clarify the element info of the smbios structure. + + Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.
+ (C) Copyright 2017 - 2019 Hewlett Packard Enterprise Development LP
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SMBIOS_PRINT_INFO_H_ +#define _SMBIOS_PRINT_INFO_H_ + +#include + +extern UINT8 SmbiosMajorVersion; +extern UINT8 SmbiosMinorVersion; + +#define SHOW_NONE 0x00 +#define SHOW_OUTLINE 0x01 +#define SHOW_NORMAL 0x02 +#define SHOW_DETAIL 0x03 +// +// SHOW_ALL: WaitEnter() not wait input. +// +#define SHOW_ALL 0x04 +#define SHOW_STATISTICS 0x05 + +#define AS_UINT16(pData) (*((UINT16 *) pData)) +#define AS_UINT32(pData) (*((UINT32 *) pData)) +#define AS_UINT64(pData) (*((UINT64 *) pData)) + +/** + Print the info of EPS(Entry Point Structure). + + @param[in] SmbiosTable Pointer to the SMBIOS table entry point. + @param[in] Option Display option. +**/ +VOID +SmbiosPrintEPSInfo ( + IN SMBIOS_TABLE_ENTRY_POINT *SmbiosTable, + IN UINT8 Option + ); + +/** + Print the info of 64-bit EPS(Entry Point Structure). + + @param[in] SmbiosTable Pointer to the SMBIOS table entry point. + @param[in] Option Display option. +**/ +VOID +Smbios64BitPrintEPSInfo ( + IN SMBIOS_TABLE_3_0_ENTRY_POINT *SmbiosTable, + IN UINT8 Option + ); + +/** + This function print the content of the structure pointed by Struct. + + @param[in] Struct Point to the structure to be printed. + @param[in] Option Print option of information detail. + + @retval EFI_SUCCESS Successfully Printing this function. + @retval EFI_INVALID_PARAMETER Invalid Structure. + @retval EFI_UNSUPPORTED Unsupported. +**/ +EFI_STATUS +SmbiosPrintStructure ( + IN SMBIOS_STRUCTURE_POINTER *Struct, + IN UINT8 Option + ); + +/** + Display BIOS Information (Type 0) information. + + @param[in] Chara The information bits. + @param[in] Option The optional information. +**/ +VOID +DisplayBiosCharacteristics ( + IN UINT64 Chara, + IN UINT8 Option + ); + +/** + Display Bios Characteristice extensions1 information. + + @param[in] Byte1 The information. + @param[in] Option The optional information. +**/ +VOID +DisplayBiosCharacteristicsExt1 ( + IN UINT8 Byte1, + IN UINT8 Option + ); + +/** + Display Bios Characteristice extensions2 information. + + @param[in] Byte2 The information. + @param[in] Option The optional information. +**/ +VOID +DisplayBiosCharacteristicsExt2 ( + IN UINT8 Byte2, + IN UINT8 Option + ); + +/** + Display Processor Information (Type 4) information. + + @param[in] Family The family value. + @param[in] Option The option value. +**/ +VOID +DisplayProcessorFamily ( + UINT8 Family, + UINT8 Option + ); + +/** + Display processor family information. + + @param[in] Family2 The family value. + @param[in] Option The option value. +**/ +VOID +DisplayProcessorFamily2 ( + IN UINT16 Family2, + IN UINT8 Option + ); + +/** + Display processor voltage information. + + @param[in] Voltage The Voltage. + Bit 7 Set to 0, indicating 'legacy' mode for processor voltage + Bits 6:4 Reserved, must be zero + Bits 3:0 Voltage Capability. + A Set bit indicates that the voltage is supported. + Bit 0 - 5V + Bit 1 - 3.3V + Bit 2 - 2.9V + Bit 3 - Reserved, must be zero. + + Note: + Setting of multiple bits indicates the socket is configurable + If bit 7 is set to 1, the remaining seven bits of the field are set to + contain the processor's current voltage times 10. + For example, the field value for a processor voltage of 1.8 volts would be + 92h = 80h + (1.8 * 10) = 80h + 18 = 80h +12h. + + @param[in] Option The option. +**/ +VOID +DisplayProcessorVoltage ( + IN UINT8 Voltage, + IN UINT8 Option + ); + +/** + Display processor information. + + @param[in] Status The status. +Bit 7 Reserved, must be 0 +Bit 6 CPU Socket Populated + 1 - CPU Socket Populated + 0 - CPU Socket Unpopulated +Bits 5:3 Reserved, must be zero +Bits 2:0 CPU Status + 0h - Unknown + 1h - CPU Enabled + 2h - CPU Disabled by User via BIOS Setup + 3h - CPU Disabled By BIOS (POST Error) + 4h - CPU is Idle, waiting to be enabled. + 5-6h - Reserved + 7h - Other + + @param[in] Option The option +**/ +VOID +DisplayProcessorStatus ( + IN UINT8 Status, + IN UINT8 Option + ); + +/** + Display information about Memory Controller Information (Type 5). + + @param[in] Size Memory size. + @param[in] SlotNum Which slot is this about. + @param[in] Option Option for the level of detail output required. +**/ +VOID +DisplayMaxMemoryModuleSize ( + IN UINT8 Size, + IN UINT8 SlotNum, + IN UINT8 Option + ); + +/** + Display information about memory configuration handles. + + @param[in] Handles The buffer of handles to output info on. + @param[in] SlotNum The number of handles in the above buffer. + @param[in] Option Option for the level of detail output required. +**/ +VOID +DisplayMemoryModuleConfigHandles ( + IN UINT16 *Handles, + IN UINT8 SlotNum, + IN UINT8 Option + ); + +/** + Display Memory Module Information (Type 6). + + @param[in] BankConnections + @param[in] Option +**/ +VOID +DisplayMmBankConnections ( + IN UINT8 BankConnections, + IN UINT8 Option + ); + +/** + Display memory informcation. + + Bits 0:6 Size (n), + where 2**n is the size in MB with three special-case values: + 7Dh Not determinable (Installed Size only) + 7Eh Module is installed, but no memory has been enabled + 7Fh Not installed + Bit 7 Defines whether the memory module has a single- (0) + or double-bank (1) connection. + + @param[in] Size - The size + @param[in] Option - The option +**/ +VOID +DisplayMmMemorySize ( + IN UINT8 Size, + IN UINT8 Option + ); + +/** + Display Cache Configuration. + + @param[in] CacheConfiguration Cache Configuration. +Bits 15:10 Reserved, must be 0 +Bits 9:8 Operational Mode + 0h - Write Through + 1h - Write Back + 2h - Varies with Memory Address + 3h - Unknown +Bit 7 Enabled/Disabled + 1 - Enabled + 0 - Disabled +Bits 6:5 Location + 0h - Internal + 1h - External + 2h - Reserved + 3h - Unknown +Bit 4 Reserved, must be zero +Bit 3 Cache Socketed + 1 - Socketed + 0 - Unsocketed +Bits 2:0 Cache Level + 1 through 8 (For example, an L1 cache would + use value 000b and an L3 cache would use 010b.) + + @param[in] Option The option +**/ +VOID +DisplayCacheConfiguration ( + IN UINT16 CacheConfiguration, + IN UINT8 Option + ); + +/** + The Slot ID field of the System Slot structure provides a mechanism to + correlate the physical attributes of the slot to its logical access method + (which varies based on the Slot Type field). + + @param[in] SlotId - The slot ID + @param[in] SlotType - The slot type + @param[in] Option - The Option +**/ +VOID +DisplaySystemSlotId ( + IN UINT16 SlotId, + IN UINT8 SlotType, + IN UINT8 Option + ); + +/** + Display Portable Battery (Type 22) information. + + The date the cell pack was manufactured, in packed format: + Bits 15:9 Year, biased by 1980, in the range 0 to 127. + Bits 8:5 Month, in the range 1 to 12. + Bits 4:0 Date, in the range 1 to 31. + For example, 01 February 2000 would be identified as + 0010 1000 0100 0001b (0x2841). + + @param[in] Date The date + @param[in] Option The option +**/ +VOID +DisplaySBDSManufactureDate ( + IN UINT16 Date, + IN UINT8 Option + ); + +/** + Display System Reset (Type 23) information. + + Routine Description: + Identifies the system-reset capabilities for the system. + Bits 7:6 Reserved for future assignment via this specification, set to 00b. + Bit 5 System contains a watchdog timer, either True (1) or False (0). + Bits 4:3 Boot Option on Limit. + Identifies the system action to be taken when the Reset Limit is reached, one of: + 00b Reserved, do not use. + 01b Operating system + 10b System utilities + 11b Do not rebootBits + 2:1 Boot Option. Indicates the action to be taken following a watchdog reset, one of: + 00b Reserved, do not use. + 01b Operating system + 10b System utilities + 11b Do not reboot + Bit 0 Status. + 1b The system reset is enabled by the user + 0b The system reset is not enabled by the user + + @param[in] Reset Reset + @param[in] Option The option +**/ +VOID +DisplaySystemResetCapabilities ( + IN UINT8 Reset, + IN UINT8 Option + ); + +/** + Display Hardware Security (Type 24) information. + + Routine Description: + Identifies the password and reset status for the system: + + Bits 7:6 Power-on Password Status, one of: + 00b Disabled + 01b Enabled + 10b Not Implemented + 11b Unknown + Bits 5:4 Keyboard Password Status, one of: + 00b Disabled + 01b Enabled + 10b Not Implemented + 11b Unknown + Bits 3:2 Administrator Password Status, one of: + 00b Disabled + 01b Enabled + 10b Not Implemented + 11b Unknown + Bits 1:0 Front Panel Reset Status, one of: + 00b Disabled + 01b Enabled + 10b Not Implemented + 11b Unknown + + @param[in] Settings The device settings. + @param[in] Option The device options. +**/ +VOID +DisplayHardwareSecuritySettings ( + IN UINT8 Settings, + IN UINT8 Option + ); + +/** + Display Out-of-Band Remote Access (Type 30) information. + + @param[in] Connections The device characteristics. + @param[in] Option The device options. +**/ +VOID +DisplayOBRAConnections ( + IN UINT8 Connections, + IN UINT8 Option + ); + +/** + Display System Boot Information (Type 32) information. + + @param[in] Parameter The parameter. + @param[in] Option The options. +**/ +VOID +DisplaySystemBootStatus ( + IN UINT8 Parameter, + IN UINT8 Option + ); + +/** + Display System Power Supply (Type 39) information. + + @param[in] Characteristics The device characteristics. + @param[in] Option The device options. +**/ +VOID +DisplaySPSCharacteristics ( + IN UINT16 Characteristics, + IN UINT8 Option + ); + +/** + Display TPM Device (Type 43) Characteristics. + + @param[in] Chara The information bits. + @param[in] Option The optional information. +**/ +VOID +DisplayTpmDeviceCharacteristics ( + IN UINT64 Chara, + IN UINT8 Option + ); + +/** + Display Processor Architecture Type (Type 44). + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayProcessorArchitectureType ( + IN UINT8 Key, + IN UINT8 Option + ); +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/QueryTable.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/QueryTable.c new file mode 100644 index 00000000..064bed3d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/QueryTable.c @@ -0,0 +1,4836 @@ +/** @file + Build a table, each item is (Key, Info) pair. + And give a interface of query a string out of a table. + + Copyright (c) 2005 - 2019, Intel Corporation. All rights reserved.
+ (C) Copyright 2016-2019 Hewlett Packard Enterprise Development LP
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDebug1CommandsLib.h" +#include "QueryTable.h" +#include "PrintInfo.h" + +TABLE_ITEM SystemWakeupTypeTable[] = { + { + 0x0, + L" Reserved" + }, + { + 0x1, + L" Other" + }, + { + 0x2, + L" Unknown" + }, + { + 0x3, + L" APM Timer" + }, + { + 0x4, + L" Modem Ring" + }, + { + 0x5, + L" LAN Remote" + }, + { + 0x6, + L" Power Switch" + }, + { + 0x7, + L" AC Power Restored" + } +}; + +TABLE_ITEM BaseBoardFeatureFlagsTable[] = { + { + 0, + L" Hosting board" + }, + { + 1, + L" Requires at least one daughter board or auxiliary card" + }, + { + 2, + L" Removable" + }, + { + 3, + L" Replaceable" + }, + { + 4, + L" Hot swappable" + } +}; + +TABLE_ITEM BaseBoardBoardTypeTable[] = { + { + 0x01, + L" Unknown" + }, + { + 0x02, + L" Other" + }, + { + 0x03, + L" Server Blade" + }, + { + 0x04, + L" Connectivity Switch" + }, + { + 0x05, + L" System Management Module" + }, + { + 0x06, + L" Processor Module" + }, + { + 0x07, + L" I/O Module" + }, + { + 0x08, + L" Memory Module" + }, + { + 0x09, + L" Daughter board" + }, + { + 0x0A, + L" Motherboard" + }, + { + 0x0B, + L" Processor/Memory Module" + }, + { + 0x0C, + L" Processor/IO Module" + }, + { + 0x0D, + L" Interconnect Board" + } +}; + +TABLE_ITEM SystemEnclosureTypeTable[] = { + { + 0x01, + L" Other" + }, + { + 0x02, + L" Unknown" + }, + { + 0x03, + L" Desktop" + }, + { + 0x04, + L" Low Profile Desktop" + }, + { + 0x05, + L" Pizza Box" + }, + { + 0x06, + L" Mini Tower" + }, + { + 0x07, + L" Tower" + }, + { + 0x08, + L" Portable" + }, + { + 0x09, + L" Laptop" + }, + { + 0x0A, + L" Notebook" + }, + { + 0x0B, + L" Hand Held" + }, + { + 0x0C, + L" Docking Station" + }, + { + 0x0D, + L" All in One" + }, + { + 0x0E, + L" Sub Notebook" + }, + { + 0x0F, + L" Space-saving" + }, + { + 0x10, + L" Lunch Box" + }, + { + 0x11, + L" Main Server Chassis" + }, + { + 0x12, + L" Expansion Chassis" + }, + { + 0x13, + L" SubChassis" + }, + { + 0x14, + L" Bus Expansion Chassis" + }, + { + 0x15, + L" Peripheral Chassis" + }, + { + 0x16, + L" RAID Chassis" + }, + { + 0x17, + L" Rack Mount Chassis" + }, + { + 0x18, + L" Sealed-case PC" + }, + { + 0x19, + L" Multi-system Chassis" + }, + { + 0x1A, + L" CompactPCI" + }, + { + 0x1B, + L" AdvancedTCA" + }, + { + 0x1C, + L" Blade" + }, + { + 0x1D, + L" Blade Enclosure" + }, + { + 0x1E, + L" Tablet" + }, + { + 0x1F, + L" Convertible" + }, + { + 0x20, + L" Detachable" + }, + { + 0x21, + L" IoT Gateway" + }, + { + 0x22, + L" Embedded PC" + }, + { + 0x23, + L" Mini PC" + }, + { + 0x24, + L" Stick PC" + }, +}; + +TABLE_ITEM SystemEnclosureStatusTable[] = { + { + 0x1, + L" Other" + }, + { + 0x2, + L" Unknown" + }, + { + 0x3, + L" Safe" + }, + { + 0x4, + L" Warning" + }, + { + 0x5, + L" Critical" + }, + { + 0x6, + L" Non-recoverable" + } +}; + +TABLE_ITEM SESecurityStatusTable[] = { + { + 0x1, + L" Other" + }, + { + 0x2, + L" Unknown" + }, + { + 0x3, + L" None" + }, + { + 0x4, + L" External interface locked out" + }, + { + 0x5, + L" External interface enabled" + } +}; + +TABLE_ITEM ProcessorTypeTable[] = { + { + 0x1, + L" Other" + }, + { + 0x2, + L" Unknown" + }, + { + 0x3, + L" Central Processor" + }, + { + 0x4, + L" Math Processor" + }, + { + 0x5, + L" DSP Processor" + }, + { + 0x6, + L" Video Processor " + }, +}; + +TABLE_ITEM ProcessorUpgradeTable[] = { + { + 0x01, + L"Other" + }, + { + 0x02, + L"Unknown" + }, + { + 0x03, + L"Daughter Board" + }, + { + 0x04, + L"ZIF Socket" + }, + { + 0x05, + L"Replaceable Piggy Back" + }, + { + 0x06, + L"None" + }, + { + 0x07, + L"LIF Socket" + }, + { + 0x08, + L"Slot 1" + }, + { + 0x09, + L"Slot 2" + }, + { + 0x0A, + L"370-pin socket" + }, + { + 0x0B, + L"Slot A" + }, + { + 0x0C, + L"Slot M" + }, + { + 0x0D, + L"Socket 423" + }, + { + 0x0E, + L"Socket A" + }, + { + 0x0F, + L"Socket 478" + }, + { + 0x10, + L"Socket 754" + }, + { + 0x11, + L"Socket 940" + }, + { + 0x12, + L"Socket 939" + }, + { + 0x13, + L"Socket mPGA604" + }, + { + 0x14, + L"Socket LGA771" + }, + { + 0x15, + L"Socket LGA775" + }, + { + 0x16, + L"Socket S1" + }, + { + 0x17, + L"Socket AM2" + }, + { + 0x18, + L"Socket F" + }, + { + 0x19, + L"Socket LGA1366" + }, + { + 0x1A, + L"Socket G34" + }, + { + 0x1B, + L"Socket AM3" + }, + { + 0x1C, + L"Socket C32" + }, + { + 0x1D, + L"Socket LGA1156" + }, + { + 0x1E, + L"Socket LGA1567" + }, + { + 0x1F, + L"Socket PGA988A" + }, + { + 0x20, + L"Socket BGA1288" + }, + { + 0x21, + L"Socket rPGA988B" + }, + { + 0x22, + L"Socket BGA1023" + }, + { + 0x23, + L"Socket BGA1224" + }, + { + 0x24, + L"Socket LGA1155" + }, + { + 0x25, + L"Socket LGA1356" + }, + { + 0x26, + L"Socket LGA2011" + }, + { + 0x27, + L"Socket FS1" + }, + { + 0x28, + L"Socket FS2" + }, + { + 0x29, + L"Socket FM1" + }, + { + 0x2A, + L"Socket FM2" + }, + { + 0x2B, + L"Socket LGA2011-3" + }, + { + 0x2C, + L"Socket LGA1356-3" + }, + { + 0x2D, + L"Socket LGA1150" + }, + { + 0x2E, + L"Socket BGA1168" + }, + { + 0x2F, + L"Socket BGA1234" + }, + { + 0x30, + L"Socket BGA1364" + }, + { + 0x31, + L"Socket AM4" + }, + { + 0x32, + L"Socket LGA1151" + }, + { + 0x33, + L"Socket BGA1356" + }, + { + 0x34, + L"Socket BGA1440" + }, + { + 0x35, + L"Socket BGA1515" + }, + { + 0x36, + L"Socket LGA3647-1" + }, + { + 0x37, + L"Socket SP3" + }, + { + 0x38, + L"Socket SP3r2" + }, + { + 0x39, + L"Socket LGA2066" + }, + { + 0x3A, + L"Socket BGA1392" + }, + { + 0x3B, + L"Socket BGA1510" + }, + { + 0x3C, + L"Socket BGA1528" + } +}; + +TABLE_ITEM ProcessorCharacteristicsTable[] = { + { + 1, + L" Unknown" + }, + { + 2, + L" 64-bit Capable" + }, + { + 3, + L" Multi-Core" + }, + { + 4, + L" Hardware Thread" + }, + { + 5, + L" Execute Protection" + }, + { + 6, + L" Enhanced Virtualization" + }, + { + 7, + L" Power/Performance Control" + }, + { + 8, + L" 128-bit Capable" + }, + { + 9, + L" ARM64 SoC ID" + } +}; + + +TABLE_ITEM McErrorDetectMethodTable[] = { + { + 0x01, + L"Other" + }, + { + 0x02, + L"Unknown" + }, + { + 0x03, + L"None" + }, + { + 0x04, + L"8-bit Parity" + }, + { + 0x05, + L"32-bit ECC" + }, + { + 0x06, + L"64-bit ECC" + }, + { + 0x07, + L"128-bit ECC" + }, + { + 0x08, + L"CRC" + }, +}; + +TABLE_ITEM McErrorCorrectCapabilityTable[] = { + { + 0, + L"Other" + }, + { + 1, + L"Unknown" + }, + { + 2, + L"None" + }, + { + 3, + L"Single Bit Error Correcting" + }, + { + 4, + L"Double Bit Error Correcting" + }, + { + 5, + L"Error Scrubbing" + }, +}; + +TABLE_ITEM McInterleaveSupportTable[] = { + { + 0x01, + L"Other" + }, + { + 0x02, + L"Unknown" + }, + { + 0x03, + L"One Way Interleave" + }, + { + 0x04, + L"Two Way Interleave" + }, + { + 0x05, + L"Four Way Interleave" + }, + { + 0x06, + L"Eight Way Interleave" + }, + { + 0x07, + L"Sixteen Way Interleave" + } +}; + +TABLE_ITEM McMemorySpeedsTable[] = { + { + 0, + L" Other" + }, + { + 1, + L" Unknown" + }, + { + 2, + L" 70ns" + }, + { + 3, + L" 60ns" + }, + { + 4, + L" 50ns" + }, +}; + +TABLE_ITEM MemoryModuleVoltageTable[] = { + { + 0, + L" 5V" + }, + { + 1, + L" 3.3V" + }, + { + 2, + L" 2.9V" + }, +}; + +TABLE_ITEM MmMemoryTypeTable[] = { + { + 0, + L" Other" + }, + { + 1, + L" Unknown" + }, + { + 2, + L" Standard" + }, + { + 3, + L" Fast Page Mode" + }, + { + 4, + L" EDO" + }, + { + 5, + L" Parity" + }, + { + 6, + L" ECC " + }, + { + 7, + L" SIMM" + }, + { + 8, + L" DIMM" + }, + { + 9, + L" Burst EDO" + }, + { + 10, + L" SDRAM" + } +}; + +TABLE_ITEM MmErrorStatusTable[] = { + { + 0, + L" Uncorrectable errors received" + }, + { + 1, + L" Correctable errors received" + }, + { + 2, + L" Error Status obtained from the event log" + } +}; + +TABLE_ITEM CacheSRAMTypeTable[] = { + { + 0, + L" Other" + }, + { + 1, + L" Unknown" + }, + { + 2, + L" Non-Burst" + }, + { + 3, + L" Burst" + }, + { + 4, + L" Pipeline Burst" + }, + { + 5, + L" Synchronous" + }, + { + 6, + L" Asynchronous" + }, +}; + +TABLE_ITEM CacheErrCorrectingTypeTable[] = { + { + 0x01, + L"Other" + }, + { + 0x02, + L"Unknown" + }, + { + 0x03, + L"None" + }, + { + 0x04, + L"Parity" + }, + { + 0x05, + L"Single-bit ECC" + }, + { + 0x06, + L"Multi-bit ECC" + } +}; + +TABLE_ITEM CacheSystemCacheTypeTable[] = { + { + 0x01, + L"Other" + }, + { + 0x02, + L"Unknown" + }, + { + 0x03, + L"Instruction" + }, + { + 0x04, + L"Data" + }, + { + 0x05, + L"Unified" + } +}; + +TABLE_ITEM CacheAssociativityTable[] = { + { + 0x01, + L"Other" + }, + { + 0x02, + L"Unknown" + }, + { + 0x03, + L"Direct Mapped" + }, + { + 0x04, + L"2-way Set-Associative" + }, + { + 0x05, + L"4-way Set-Associative" + }, + { + 0x06, + L"Fully Associative" + }, + { + 0x07, + L"8-way Set-Associative" + }, + { + 0x08, + L"16-way Set-Associative" + }, + { + 0x09, + L"12-way Set-Associative" + }, + { + 0x0A, + L"24-way Set-Associative" + }, + { + 0x0B, + L"32-way Set-Associative" + }, + { + 0x0C, + L"48-way Set-Associative" + }, + { + 0x0D, + L"64-way Set-Associative" + }, + { + 0x0E, + L"20-way Set-Associative" + } +}; + +TABLE_ITEM PortConnectorTypeTable[] = { + { + 0x00, + L"None" + }, + { + 0x01, + L"Centronics" + }, + { + 0x02, + L"Mini Centronics" + }, + { + 0x03, + L"Proprietary" + }, + { + 0x04, + L"DB-25 pin male" + }, + { + 0x05, + L"DB-25 pin female" + }, + { + 0x06, + L"DB-15 pin male" + }, + { + 0x07, + L"DB-15 pin female" + }, + { + 0x08, + L"DB-9 pin male" + }, + { + 0x09, + L"DB-9 pin female" + }, + { + 0x0A, + L"RJ-11" + }, + { + 0x0B, + L"RJ-45" + }, + { + 0x0C, + L"50 Pin MiniSCSI" + }, + { + 0x0D, + L"Mini-DIN" + }, + { + 0x0E, + L"Micro-DIN" + }, + { + 0x0F, + L"PS/2" + }, + { + 0x10, + L"Infrared" + }, + { + 0x11, + L"HP-HIL" + }, + { + 0x12, + L"Access Bus (USB)" + }, + { + 0x13, + L"SSA SCSI" + }, + { + 0x14, + L"Circular DIN-8 male" + }, + { + 0x15, + L"Circular DIN-8 female" + }, + { + 0x16, + L"On Board IDE" + }, + { + 0x17, + L"On Board Floppy" + }, + { + 0x18, + L"9 Pin Dual Inline (pin 10 cut)" + }, + { + 0x19, + L"25 Pin Dual Inline (pin 26 cut)" + }, + { + 0x1A, + L"50 Pin Dual Inline" + }, + { + 0x1B, + L"68 Pin Dual Inline" + }, + { + 0x1C, + L"On Board Sound Input from CD-ROM" + }, + { + 0x1D, + L"Mini-Centronics Type-14" + }, + { + 0x1E, + L"Mini-Centronics Type-26" + }, + { + 0x1F, + L"Mini-jack (headphones)" + }, + { + 0x20, + L"BNC" + }, + { + 0x21, + L"1394" + }, + { + 0x22, + L"SAS/SATA Plug Receptacle" + }, + { + 0x23, + L"USB Type-C Receptacle" + }, + { + 0xA0, + L"PC-98" + }, + { + 0xA1, + L"PC-98Hireso" + }, + { + 0xA2, + L"PC-H98" + }, + { + 0xA3, + L"PC-98Note" + }, + { + 0xA4, + L"PC-98Full" + }, + { + 0xFF, + L"Other" + }, +}; + +TABLE_ITEM PortTypeTable[] = { + { + 0x00, + L"None" + }, + { + 0x01, + L"Parallel Port XT/AT Compatible" + }, + { + 0x02, + L"Parallel Port PS/2" + }, + { + 0x03, + L"Parallel Port ECP" + }, + { + 0x04, + L"Parallel Port EPP" + }, + { + 0x05, + L"Parallel Port ECP/EPP" + }, + { + 0x06, + L"Serial Port XT/AT Compatible" + }, + { + 0x07, + L"Serial Port 16450 Compatible" + }, + { + 0x08, + L"Serial Port 16550 Compatible" + }, + { + 0x09, + L"Serial Port 16550A Compatible" + }, + { + 0x0A, + L"SCSI Port" + }, + { + 0x0B, + L"MIDI Port" + }, + { + 0x0C, + L"Joy Stick Port" + }, + { + 0x0D, + L"Keyboard Port" + }, + { + 0x0E, + L"Mouse Port" + }, + { + 0x0F, + L"SSA SCSI" + }, + { + 0x10, + L"USB" + }, + { + 0x11, + L"FireWire (IEEE P1394)" + }, + { + 0x12, + L"PCMCIA Type II" + }, + { + 0x13, + L"PCMCIA Type II" + }, + { + 0x14, + L"PCMCIA Type III" + }, + { + 0x15, + L"Cardbus" + }, + { + 0x16, + L"Access Bus Port" + }, + { + 0x17, + L"SCSI II" + }, + { + 0x18, + L"SCSI Wide" + }, + { + 0x19, + L"PC-98" + }, + { + 0x1A, + L"PC-98-Hireso" + }, + { + 0x1B, + L"PC-H98" + }, + { + 0x1C, + L"Video Port" + }, + { + 0x1D, + L"Audio Port" + }, + { + 0x1E, + L"Modem Port" + }, + { + 0x1F, + L"Network Port" + }, + { + 0x20, + L"SATA Port" + }, + { + 0x21, + L"SAS Port" + }, + { + 0x22, + L"Multi-Function Display Port (MFDP)" + }, + { + 0x23, + L"Thunderbolt" + }, + { + 0xA0, + L"8251 Compatible" + }, + { + 0xA1, + L"8251 FIFO Compatible" + }, + { + 0xFF, + L"Other " + }, +}; + +TABLE_ITEM SystemSlotTypeTable[] = { + { + 0x01, + L"Other" + }, + { + 0x02, + L"Unknown" + }, + { + 0x03, + L"ISA" + }, + { + 0x04, + L"MCA" + }, + { + 0x05, + L"EISA" + }, + { + 0x06, + L"PCI" + }, + { + 0x07, + L"PC Card (PCMCIA)" + }, + { + 0x08, + L"VL-VESA" + }, + { + 0x09, + L"Proprietary" + }, + { + 0x0A, + L"Processor Card Slot" + }, + { + 0x0B, + L"Proprietary Memory Card Slot" + }, + { + 0x0C, + L"I/O Riser Card Slot" + }, + { + 0x0D, + L"NuBus" + }, + { + 0x0E, + L"PCI - 66MHz Capable" + }, + { + 0x0F, + L"AGP" + }, + { + 0x10, + L"AGP 2X" + }, + { + 0x11, + L"AGP 4X" + }, + { + 0x12, + L"PCI-X" + }, + { + 0x13, + L"AGP 8X" + }, + { + 0x14, + L"M.2 Socket 1-DP (Mechanical Key A)" + }, + { + 0x15, + L"M.2 Socket 1-SD (Mechanical Key E)" + }, + { + 0x16, + L"M.2 Socket 2 (Mechanical Key B)" + }, + { + 0x17, + L"M.2 Socket 3 (Mechanical Key M)" + }, + { + 0x18, + L"MXM Type I" + }, + { + 0x19, + L"MXM Type II" + }, + { + 0x1A, + L"MXM Type III (standard connector)" + }, + { + 0x1B, + L"MXM Type III (HE connector)" + }, + { + 0x1C, + L"MXM Type IV" + }, + { + 0x1D, + L"MXM 3.0 Type A" + }, + { + 0x1E, + L"MXM 3.0 Type B" + }, + { + 0x1F, + L"PCI Express Gen 2 SFF-8639" + }, + { + 0x20, + L"PCI Express Gen 3 SFF-8639" + }, + { + 0x21, + L"PCI Express Mini 52-pin (CEM spec. 2.0) with bottom-side keep-outs" + }, + { + 0x22, + L"PCI Express Mini 52-pin (CEM spec. 2.0) without bottom-side keep-outs" + }, + { + 0x23, + L"PCI Express Mini 76-pin (CEM spec. 2.0) Corresponds to Display-Mini card" + }, + { + SlotTypeCXLFlexbus10, + L"CXL Flexbus 1.0" + }, + { + 0xA0, + L"PC-98/C20 " + }, + { + 0xA1, + L"PC-98/C24 " + }, + { + 0xA2, + L"PC-98/E " + }, + { + 0xA3, + L"PC-98/Local Bus " + }, + { + 0xA4, + L"PC-98/Card " + }, + { + 0xA5, + L"PCI Express " + }, + { + 0xA6, + L"PCI Express X1" + }, + { + 0xA7, + L"PCI Express X2" + }, + { + 0xA8, + L"PCI Express X4" + }, + { + 0xA9, + L"PCI Express X8" + }, + { + 0xAA, + L"PCI Express X16" + }, + { + 0xAB, + L"PCI Express Gen 2" + }, + { + 0xAC, + L"PCI Express Gen 2 X1" + }, + { + 0xAD, + L"PCI Express Gen 2 X2" + }, + { + 0xAE, + L"PCI Express Gen 2 X4" + }, + { + 0xAF, + L"PCI Express Gen 2 X8" + }, + { + 0xB0, + L"PCI Express Gen 2 X16" + }, + { + 0xB1, + L"PCI Express Gen 3" + }, + { + 0xB2, + L"PCI Express Gen 3 X1" + }, + { + 0xB3, + L"PCI Express Gen 3 X2" + }, + { + 0xB4, + L"PCI Express Gen 3 X4" + }, + { + 0xB5, + L"PCI Express Gen 3 X8" + }, + { + 0xB6, + L"PCI Express Gen 3 X16" + }, + { + SlotTypePciExpressGen4, + L"PCI Express Gen 4" + }, + { + SlotTypePciExpressGen4X1, + L"PCI Express Gen 4 X1" + }, + { + SlotTypePciExpressGen4X2, + L"PCI Express Gen 4 X2" + }, + { + SlotTypePciExpressGen4X4, + L"PCI Express Gen 4 X4" + }, + { + SlotTypePciExpressGen4X8, + L"PCI Express Gen 4 X8" + }, + { + SlotTypePciExpressGen4X16, + L"PCI Express Gen 4 X16" + } +}; + +TABLE_ITEM SystemSlotDataBusWidthTable[] = { + { + 0x01, + L" Other" + }, + { + 0x02, + L" Unknown" + }, + { + 0x03, + L" 8 bit" + }, + { + 0x04, + L" 16 bit" + }, + { + 0x05, + L" 32 bit" + }, + { + 0x06, + L" 64 bit" + }, + { + 0x07, + L" 128 bit" + }, + { + 0x08, + L" 1x or x1" + }, + { + 0x09, + L" 2x or x2" + }, + { + 0x0A, + L" 4x or x4" + }, + { + 0x0B, + L" 8x or x8" + }, + { + 0x0C, + L" 12x or x12" + }, + { + 0x0D, + L" 16x or x16" + }, + { + 0x0E, + L" 32x or x32" + } +}; + +TABLE_ITEM SystemSlotCurrentUsageTable[] = { + { + 0x01, + L" Other" + }, + { + 0x02, + L" Unknown" + }, + { + 0x03, + L" Available" + }, + { + 0x04, + L" In use" + }, + { + 0x05, + L" Unavailable" + } +}; + +TABLE_ITEM SystemSlotLengthTable[] = { + { + 0x01, + L" Other" + }, + { + 0x02, + L" Unknown" + }, + { + 0x03, + L" Short length" + }, + { + 0x04, + L" Long Length" + }, +}; + +TABLE_ITEM SlotCharacteristics1Table[] = { + { + 0, + L" Characteristics Unknown" + }, + { + 1, + L" Provides 5.0 Volts" + }, + { + 2, + L" Provides 3.3 Volts" + }, + { + 3, + L" Slot's opening is shared with another slot, e.g. PCI/EISA shared slot." + }, + + { + 4, + L" PC Card slot supports PC Card-16" + }, + { + 5, + L" PC Card slot supports CardBus" + }, + { + 6, + L" PC Card slot supports Zoom Video " + }, + { + 7, + L" PC Card slot supports Modem Ring Resume " + } +}; + +TABLE_ITEM SlotCharacteristics2Table[] = { + { + 0, + L" PCI slot supports Power Management Enable (PME#) signal" + }, + { + 1, + L" Slot supports hot-plug devices" + }, + { + 2, + L" PCI slot supports SMBus signal" + }, + { + 3, + L" PCIe slot supports bifurcation" + } +}; + +TABLE_ITEM OnboardDeviceTypesTable[] = { + { + 0x01, + L" Other" + }, + { + 0x02, + L" Unknown" + }, + { + 0x03, + L" Video" + }, + { + 0x04, + L" SCSI Controller" + }, + { + 0x05, + L" Ethernet" + }, + { + 0x06, + L" Token Ring" + }, + { + 0x07, + L" Sound" + }, + { + 0x08, + L" Pata Controller" + }, + { + 0x09, + L" Sata Controller" + }, + { + 0x0A, + L" Sas Controller" + }, +}; + +TABLE_ITEM SELTypesTable[] = { + { + 0x00, + L" Reserved." + }, + { + 0x01, + L" Single-bit ECC memory error" + }, + { + 0x02, + L" Multi-bit ECC memory error" + }, + { + 0x03, + L" Parity memory error" + }, + { + 0x04, + L" Bus time-out" + }, + { + 0x05, + L" I/O Channel Check" + }, + { + 0x06, + L" Software NMI" + }, + { + 0x07, + L" POST Memory Resize" + }, + { + 0x08, + L" POST Error" + }, + { + 0x09, + L" PCI Parity Error" + }, + { + 0x0A, + L" PCI System Error" + }, + { + 0x0B, + L" CPU Failure" + }, + { + 0x0C, + L" EISA FailSafe Timer time-out" + }, + { + 0x0D, + L" Correctable memory log disabled" + }, + { + 0x0E, + L" Logging disabled for a specific Event Type" + }, + { + 0x0F, + L" Reserved" + }, + { + 0x10, + L" System Limit Exceeded" + }, + { + 0x11, + L" Asynchronous hardware timer expired and issued a system reset" + }, + { + 0x12, + L" System configuration information" + }, + { + 0x13, + L" Hard-disk information" + }, + { + 0x14, + L" System reconfigured" + }, + { + 0x15, + L" Uncorrectable CPU-complex error" + }, + { + 0x16, + L" Log Area Reset/Cleared" + }, + { + 0x17, + L" System boot" + }, + { + 0x7F18, + L" Unused by SMBIOS specification" + }, + { + 0xFE80, + L" System and OEM specified" + }, + { + 0xFF, + L" End-of-log" + }, +}; + +TABLE_ITEM SELVarDataFormatTypeTable[] = { + { + 0x00, + L" None " + }, + { + 0x01, + L" Handle " + }, + { + 0x02, + L" Multiple-Event " + }, + { + 0x03, + L" Multiple-Event Handle " + }, + { + 0x04, + L" POST Results Bitmap " + }, + // + // Defined below + // + { + 0x05, + L" System Management Type" + }, + // + // Defined below + // + { + 0x06, + L" Multiple-Event System Management Type " + }, + { + 0x7F07, + L" Unused " + }, + { + 0xFF80, + L" OEM assigned " + }, +}; + +TABLE_ITEM PostResultsBitmapDw1Table[] = { + { + 0, + L" Channel 2 Timer error " + }, + { + 1, + L" Master PIC (8259 #1) error " + }, + { + 2, + L" Slave PIC (8259 #2) error " + }, + { + 3, + L" CMOS Battery Failure " + }, + { + 4, + L" CMOS System Options Not Set " + }, + { + 5, + L" CMOS Checksum Error " + }, + { + 6, + L" CMOS Configuration Error " + }, + { + 7, + L" Mouse and Keyboard Swapped " + }, + { + 8, + L" Keyboard Locked " + }, + { + 9, + L" Keyboard Not Functional " + }, + { + 10, + L" Keyboard Controller Not Functional " + }, + { + 11, + L" CMOS Memory Size Different " + }, + { + 12, + L" Memory Decreased in Size " + }, + { + 13, + L" Cache Memory Error " + }, + { + 14, + L" Floppy Drive 0 Error " + }, + { + 15, + L" Floppy Drive 1 Error " + }, + { + 16, + L" Floppy Controller Failure " + }, + { + 17, + L" Number of ATA Drives Reduced Error " + }, + { + 18, + L" CMOS Time Not Set " + }, + { + 19, + L" DDC Monitor Configuration Change " + }, + { + 20, + L" Reserved, set to 0 " + }, + { + 21, + L" Reserved, set to 0 " + }, + { + 22, + L" Reserved, set to 0 " + }, + { + 23, + L" Reserved, set to 0 " + }, + { + 24, + L" Second DWORD has valid data " + }, + { + 25, + L" Reserved, set to 0 " + }, + { + 26, + L" Reserved, set to 0 " + }, + { + 27, + L" Reserved, set to 0 " + }, + { + 28, + L" Normally 0; available for OEM assignment " + }, + { + 29, + L" Normally 0; available for OEM assignment " + }, + { + 30, + L" Normally 0; available for OEM assignment " + }, + { + 31, + L" Normally 0; available for OEM assignment " + }, +}; + +TABLE_ITEM PostResultsBitmapDw2Table[] = { + { + 0, + L" Normally 0; available for OEM assignment " + }, + { + 1, + L" Normally 0; available for OEM assignment " + }, + { + 2, + L" Normally 0; available for OEM assignment " + }, + { + 3, + L" Normally 0; available for OEM assignment " + }, + { + 4, + L" Normally 0; available for OEM assignment " + }, + { + 5, + L" Normally 0; available for OEM assignment " + }, + { + 6, + L" Normally 0; available for OEM assignment " + }, + { + 7, + L" PCI Memory Conflict " + }, + { + 8, + L" PCI I/O Conflict " + }, + { + 9, + L" PCI IRQ Conflict " + }, + { + 10, + L" PNP Memory Conflict " + }, + { + 11, + L" PNP 32 bit Memory Conflict " + }, + { + 12, + L" PNP I/O Conflict " + }, + { + 13, + L" PNP IRQ Conflict " + }, + { + 14, + L" PNP DMA Conflict " + }, + { + 15, + L" Bad PNP Serial ID Checksum " + }, + { + 16, + L" Bad PNP Resource Data Checksum " + }, + { + 17, + L" Static Resource Conflict " + }, + { + 18, + L" NVRAM Checksum Error, NVRAM Cleared " + }, + { + 19, + L" System Board Device Resource Conflict " + }, + { + 20, + L" Primary Output Device Not Found " + }, + { + 21, + L" Primary Input Device Not Found " + }, + { + 22, + L" Primary Boot Device Not Found " + }, + { + 23, + L" NVRAM Cleared By Jumper " + }, + { + 24, + L" NVRAM Data Invalid, NVRAM Cleared " + }, + { + 25, + L" FDC Resource Conflict " + }, + { + 26, + L" Primary ATA Controller Resource Conflict " + }, + { + 27, + L" Secondary ATA Controller Resource Conflict " + }, + { + 28, + L" Parallel Port Resource Conflict " + }, + { + 29, + L" Serial Port 1 Resource Conflict " + }, + { + 30, + L" Serial Port 2 Resource Conflict " + }, + { + 31, + L" Audio Resource Conflict " + }, +}; + +TABLE_ITEM SELSysManagementTypesTable[] = { + { + 0x01, + L" +2.5V Out of range, #2 " + }, + { + 0x02, + L" +3.3V Out of range " + }, + { + 0x03, + L" +5V Out of range " + }, + { + 0x04, + L" -5V Out of range " + }, + { + 0x05, + L" +12V Out of range " + }, + { + 0x06, + L" -12V Out of range " + }, + { + 0x0F07, + L" Reserved for future out-of-range voltage levels " + }, + { + 0x10, + L" System board temperature out of range " + }, + { + 0x11, + L" Processor #1 temperature out of range " + }, + { + 0x12, + L" Processor #2 temperature out of range " + }, + { + 0x13, + L" Processor #3 temperature out of range " + }, + { + 0x14, + L" Processor #4 temperature out of range " + }, + { + 0x1F15, + L" Reserved for future out-of-range temperatures" + }, + { + 0x2720, + L" Fan n (n = 0 to 7) Out of range " + }, + { + 0x2F28, + L" Reserved for future assignment via this specification " + }, + { + 0x30, + L" Chassis secure switch activated " + }, +}; + +TABLE_ITEM PMALocationTable[] = { + { + 0x01, + L" Other" + }, + { + 0x02, + L" Unknown" + }, + { + 0x03, + L" System board or motherboard" + }, + { + 0x04, + L" ISA add-on card" + }, + { + 0x05, + L" EISA add-on card" + }, + { + 0x06, + L" PCI add-on card" + }, + { + 0x07, + L" MCA add-on card" + }, + { + 0x08, + L" PCMCIA add-on card" + }, + { + 0x09, + L" Proprietary add-on card" + }, + { + 0x0A, + L" NuBus" + }, + { + 0xA0, + L" PC-98/C20 add-on card" + }, + { + 0xA1, + L" PC-98/C24 add-on card" + }, + { + 0xA2, + L" PC-98/E add-on card" + }, + { + 0xA3, + L" PC-98/Local bus add-on card" + }, + { + MemoryArrayLocationCXLFlexbus10AddonCard, + L" CXL Flexbus 1.0 add-on card" + } +}; + +TABLE_ITEM PMAUseTable[] = { + { + 0x01, + L" Other" + }, + { + 0x02, + L" Unknown" + }, + { + 0x03, + L" System memory" + }, + { + 0x04, + L" Video memory" + }, + { + 0x05, + L" Flash memory" + }, + { + 0x06, + L" Non-volatile RAM" + }, + { + 0x07, + L" Cache memory" + } +}; + +TABLE_ITEM PMAErrorCorrectionTypesTable[] = { + { + 0x01, + L" Other" + }, + { + 0x02, + L" Unknown" + }, + { + 0x03, + L" None" + }, + { + 0x04, + L" Parity" + }, + { + 0x05, + L" Single-bit ECC" + }, + { + 0x06, + L" Multi-bit ECC" + }, + { + 0x07, + L" CRC" + } +}; + +TABLE_ITEM MemoryDeviceFormFactorTable[] = { + { + 0x01, + L" Other" + }, + { + 0x02, + L" Unknown" + }, + { + 0x03, + L" SIMM" + }, + { + 0x04, + L" SIP" + }, + { + 0x05, + L" Chip" + }, + { + 0x06, + L" DIP" + }, + { + 0x07, + L" ZIP" + }, + { + 0x08, + L" Proprietary Card" + }, + { + 0x09, + L" DIMM" + }, + { + 0x0A, + L" TSOP" + }, + { + 0x0B, + L" Row of chips" + }, + { + 0x0C, + L" RIMM" + }, + { + 0x0D, + L" SODIMM" + }, + { + 0x0E, + L" SRIMM" + }, + { + 0x0F, + L" FB-DIMM" + }, + { + MemoryFormFactorDie, + L" Die" + } +}; + +TABLE_ITEM MemoryDeviceTypeTable[] = { + { + 0x01, + L" Other" + }, + { + 0x02, + L" Unknown" + }, + { + 0x03, + L" DRAM" + }, + { + 0x04, + L" EDRAM" + }, + { + 0x05, + L" VRAM" + }, + { + 0x06, + L" SRAM" + }, + { + 0x07, + L" RAM" + }, + { + 0x08, + L" ROM" + }, + { + 0x09, + L" FLASH" + }, + { + 0x0A, + L" EEPROM" + }, + { + 0x0B, + L" FEPROM" + }, + { + 0x0C, + L" EPROM" + }, + { + 0x0D, + L" CDRAM" + }, + { + 0x0E, + L" 3DRAM" + }, + { + 0x0F, + L" SDRAM" + }, + { + 0x10, + L" SGRAM" + }, + { + 0x11, + L" RDRAM" + }, + { + 0x12, + L" DDR" + }, + { + 0x13, + L" DDR2" + }, + { + 0x14, + L" DDR2 FB-DIMM" + }, + { + 0x18, + L" DDR3" + }, + { + 0x19, + L" FBD2" + }, + { + 0x1A, + L" DDR4" + }, + { + 0x1B, + L" LPDDR" + }, + { + 0x1C, + L" LPDDR2" + }, + { + 0x1D, + L" LPDDR3" + }, + { + 0x1E, + L" LPDDR4" + }, + { + 0x1F, + L" Logical non-volatile device" + }, + { + MemoryTypeHBM, + L" HBM (High Bandwidth Memory)" + }, + { + MemoryTypeHBM2, + L" HBM2 (High Bandwidth Memory Generation 2)" + }, + { + MemoryTypeDdr5, + L" DDR5" + }, + { + MemoryTypeLpddr5, + L" LPDDR5" + } +}; + +TABLE_ITEM MemoryDeviceTypeDetailTable[] = { + { + 1, + L" Other" + }, + { + 2, + L" Unknown" + }, + { + 3, + L" Fast-paged" + }, + { + 4, + L" Static column" + }, + { + 5, + L" Pseudo-STATIC" + }, + { + 6, + L" RAMBUS " + }, + { + 7, + L" Synchronous" + }, + { + 8, + L" CMOS" + }, + { + 9, + L" EDO" + }, + { + 10, + L" Window DRAM" + }, + { + 11, + L" Cache DRAM" + }, + { + 12, + L" Non-volatile" + }, + { + 13, + L" Registered(Buffered)" + }, + { + 14, + L" Unbuffered(Unregistered)" + } +}; + +TABLE_ITEM MemoryDeviceMemoryTechnologyTable[] = { + { + 0x01, + L" Other" + }, + { + 0x02, + L" Unknown" + }, + { + 0x03, + L" DRAM" + }, + { + 0x04, + L" NVDIMM-N" + }, + { + 0x05, + L" NVDIMM-F" + }, + { + 0x06, + L" NVDIMM-P" + }, + { + MemoryTechnologyIntelPersistentMemory, + L" Intel Optane DC Persistent Memory" + } +}; + +TABLE_ITEM MemoryDeviceMemoryOperatingModeCapabilityTable[] = { + { + 1, + L" Other" + }, + { + 2, + L" Unknown" + }, + { + 3, + L" Volatile memory" + }, + { + 4, + L" Byte-accessible persistent memory" + }, + { + 5, + L" Block-accessible persistent memory" + } +}; + + +TABLE_ITEM MemoryErrorTypeTable[] = { + { + 0x01, + L" Other" + }, + { + 0x02, + L" Unknown" + }, + { + 0x03, + L" OK" + }, + { + 0x04, + L" Bad read" + }, + { + 0x05, + L" Parity error" + }, + { + 0x06, + L" Single-bit error" + }, + { + 0x07, + L" Double-bit error" + }, + { + 0x08, + L" Multi-bit error" + }, + { + 0x09, + L" Nibble error" + }, + { + 0x0A, + L" Checksum error" + }, + { + 0x0B, + L" CRC error" + }, + { + 0x0C, + L" Corrected single-bit error" + }, + { + 0x0D, + L" Corrected error" + }, + { + 0x0E, + L" Uncorrectable error" + }, +}; + +TABLE_ITEM MemoryErrorGranularityTable[] = { + { + 0x01, + L" Other" + }, + { + 0x02, + L" Unknown" + }, + { + 0x03, + L" Device level" + }, + { + 0x04, + L" Memory partition level" + }, +}; + +TABLE_ITEM MemoryErrorOperationTable[] = { + { + 0x01, + L" Other" + }, + { + 0x02, + L" Unknown" + }, + { + 0x03, + L" Read" + }, + { + 0x04, + L" Write" + }, + { + 0x05, + L" Partial Write" + }, +}; + +TABLE_ITEM PointingDeviceTypeTable[] = { + { + 0x01, + L" Other" + }, + { + 0x02, + L" Unknown" + }, + { + 0x03, + L" Mouse" + }, + { + 0x04, + L" Track Ball" + }, + { + 0x05, + L" Track Point" + }, + { + 0x06, + L" Glide Point" + }, + { + 0x07, + L" Touch Pad" + }, +}; + +TABLE_ITEM PointingDeviceInterfaceTable[] = { + { + 0x01, + L" Other" + }, + { + 0x02, + L" Unknown" + }, + { + 0x03, + L" Serial" + }, + { + 0x04, + L" PS/2" + }, + { + 0x05, + L" Infrared" + }, + { + 0x06, + L" HP-HIL" + }, + { + 0x07, + L" Bus mouse" + }, + { + 0x08, + L" ADB(Apple Desktop Bus" + }, + { + 0xA0, + L" Bus mouse DB-9" + }, + { + 0xA1, + L" Bus mouse mirco-DIN" + }, + { + 0xA2, + L" USB" + }, +}; + +TABLE_ITEM PBDeviceChemistryTable[] = { + { + 0x01, + L" Other " + }, + { + 0x02, + L" Unknown " + }, + { + 0x03, + L" Lead Acid " + }, + { + 0x04, + L" Nickel Cadmium " + }, + { + 0x05, + L" Nickel metal hydride " + }, + { + 0x06, + L" Lithium-ion " + }, + { + 0x07, + L" Zinc air " + }, + { + 0x08, + L" Lithium Polymer " + }, +}; + +TABLE_ITEM VPLocationTable[] = { + { + 0x01, + L" Other " + }, + { + 0x02, + L" Unknown " + }, + { + 0x03, + L" OK " + }, + { + 0x04, + L" Non-critical " + }, + { + 0x05, + L" Critical " + }, + { + 0x06, + L" Non-recoverable " + }, +}; + +TABLE_ITEM VPStatusTable[] = { + { + 0x01, + L" Other " + }, + { + 0x02, + L" Unknown " + }, + { + 0x03, + L" Processor " + }, + { + 0x04, + L" Disk " + }, + { + 0x05, + L" Peripheral Bay " + }, + { + 0x06, + L" System Management Module " + }, + { + 0x07, + L" Motherboard " + }, + { + 0x08, + L" Memory Module " + }, + { + 0x09, + L" Processor Module " + }, + { + 0x0A, + L" Power Unit " + }, + { + 0x0B, + L" Add-in Card " + }, +}; + +TABLE_ITEM CoolingDeviceStatusTable[] = { + { + 0x01, + L" Other " + }, + { + 0x02, + L" Unknown " + }, + { + 0x03, + L" OK " + }, + { + 0x04, + L" Non-critical " + }, + { + 0x05, + L" Critical " + }, + { + 0x06, + L" Non-recoverable " + }, +}; + +TABLE_ITEM CoolingDeviceTypeTable[] = { + { + 0x01, + L" Other " + }, + { + 0x02, + L" Unknown " + }, + { + 0x03, + L" Fan " + }, + { + 0x04, + L" Centrifugal Blower " + }, + { + 0x05, + L" Chip Fan " + }, + { + 0x06, + L" Cabinet Fan " + }, + { + 0x07, + L" Power Supply Fan " + }, + { + 0x08, + L" Heat Pipe " + }, + { + 0x09, + L" Integrated Refrigeration " + }, + { + 0x10, + L" Active Cooling " + }, + { + 0x11, + L" Passive Cooling " + }, +}; + +TABLE_ITEM TemperatureProbeStatusTable[] = { + { + 0x01, + L" Other " + }, + { + 0x02, + L" Unknown " + }, + { + 0x03, + L" OK " + }, + { + 0x04, + L" Non-critical " + }, + { + 0x05, + L" Critical " + }, + { + 0x06, + L" Non-recoverable " + }, +}; + +TABLE_ITEM TemperatureProbeLocTable[] = { + { + 0x01, + L" Other " + }, + { + 0x02, + L" Unknown " + }, + { + 0x03, + L" Processor " + }, + { + 0x04, + L" Disk " + }, + { + 0x05, + L" Peripheral Bay " + }, + { + 0x06, + L" System Management Module " + }, + { + 0x07, + L" Motherboard " + }, + { + 0x08, + L" Memory Module " + }, + { + 0x09, + L" Processor Module " + }, + { + 0x0A, + L" Power Unit " + }, + { + 0x0B, + L" Add-in Card " + }, +}; + +TABLE_ITEM ECPStatusTable[] = { + { + 0x01, + L" Other " + }, + { + 0x02, + L" Unknown " + }, + { + 0x03, + L" OK " + }, + { + 0x04, + L" Non-critical " + }, + { + 0x05, + L" Critical " + }, + { + 0x06, + L" Non-recoverable " + }, +}; + +TABLE_ITEM ECPLocTable[] = { + { + 0x01, + L" Other " + }, + { + 0x02, + L" Unknown " + }, + { + 0x03, + L" Processor " + }, + { + 0x04, + L" Disk " + }, + { + 0x05, + L" Peripheral Bay " + }, + { + 0x06, + L" System Management Module " + }, + { + 0x07, + L" Motherboard " + }, + { + 0x08, + L" Memory Module " + }, + { + 0x09, + L" Processor Module " + }, + { + 0x0A, + L" Power Unit " + }, + { + 0x0B, + L" Add-in Card " + }, +}; + +TABLE_ITEM MDTypeTable[] = { + { + 0x01, + L" Other " + }, + { + 0x02, + L" Unknown " + }, + { + 0x03, + L" National Semiconductor LM75 " + }, + { + 0x04, + L" National Semiconductor LM78 " + }, + { + 0x05, + L" National Semiconductor LM79 " + }, + { + 0x06, + L" National Semiconductor LM80 " + }, + { + 0x07, + L" National Semiconductor LM81 " + }, + { + 0x08, + L" Analog Devices ADM9240 " + }, + { + 0x09, + L" Dallas Semiconductor DS1780 " + }, + { + 0x0A, + L" Maxim 1617 " + }, + { + 0x0B, + L" Genesys GL518SM " + }, + { + 0x0C, + L" Winbond W83781D " + }, + { + 0x0D, + L" Holtek HT82H791 " + }, +}; + +TABLE_ITEM MDAddressTypeTable[] = { + { + 0x01, + L" Other " + }, + { + 0x02, + L" Unknown " + }, + { + 0x03, + L" I/O Port " + }, + { + 0x04, + L" Memory " + }, + { + 0x05, + L" SM Bus " + }, +}; + +TABLE_ITEM MemoryChannelTypeTable[] = { + { + 0x01, + L" Other " + }, + { + 0x02, + L" Unknown " + }, + { + 0x03, + L" RamBus " + }, + { + 0x04, + L" SyncLink " + }, +}; + +TABLE_ITEM IPMIDIBMCInterfaceTypeTable[] = { + { + 0x00, + L" Unknown " + }, + { + 0x01, + L" KCS: Keyboard Controller Style " + }, + { + 0x02, + L" SMIC: Server Management Interface Chip " + }, + { + 0x03, + L" BT: Block Transfer " + }, + { + 0x04, + L" SSIF: SMBus System Interface " + }, + { + 0xFF05, + L" Reserved for future assignment by this specification " + }, +}; + +TABLE_ITEM MCHostInterfaceTypeTable[] = { + { + 0x3F00, + L" MCTP Host Interface " + }, + { + 0x40, + L" Network Host Interface " + }, + { + 0xF0, + L" OEM defined " + }, +}; + +TABLE_ITEM ProcessorArchitectureTypesTable[] = { + { + 0, + L" Reserved " + }, + { + 1, + L" IA32 (x86) " + }, + { + 2, + L" x64 (x86-64, intel64, AMD64, EM64T) " + }, + { + 3, + L" Intel Itanium architecture " + }, + { + 4, + L" 32-bit ARM (Aarch32) " + }, + { + 5, + L" 64-bit ARM (Aarch64) " + }, + { + 6, + L" 32-bit RISC-V (RV32) " + }, + { + 7, + L" 64-bit RISC-V (RV64) " + }, + { + 8, + L" 128-bit RISC-V (RV128) " + } +}; + +TABLE_ITEM StructureTypeInfoTable[] = { + { + 0, + L" BIOS Information" + }, + { + 1, + L" System Information" + }, + { + 2, + L" Base Board Information" + }, + { + 3, + L" System Enclosure" + }, + { + 4, + L" Processor Information" + }, + { + 5, + L" Memory Controller Information " + }, + { + 6, + L" Memory Module Information " + }, + { + 7, + L" Cache Information " + }, + { + 8, + L" Port Connector Information " + }, + { + 9, + L" System Slots " + }, + { + 10, + L" On Board Devices Information " + }, + { + 11, + L" OEM Strings" + }, + { + 12, + L" System Configuration Options " + }, + { + 13, + L" BIOS Language Information " + }, + { + 14, + L" Group Associations " + }, + { + 15, + L" System Event Log " + }, + { + 16, + L" Physical Memory Array " + }, + { + 17, + L" Memory Device " + }, + { + 18, + L" 32-bit Memory Error Information " + }, + { + 19, + L" Memory Array Mapped Address " + }, + { + 20, + L" Memory Device Mapped Address " + }, + { + 21, + L" Built-in Pointing Device " + }, + { + 22, + L" Portable Battery " + }, + { + 23, + L" System Reset " + }, + { + 24, + L" Hardware Security " + }, + { + 25, + L" System Power Controls " + }, + { + 26, + L" Voltage Probe " + }, + { + 27, + L" Cooling Device " + }, + { + 28, + L" Temperature Probe " + }, + { + 29, + L" Electrical Current Probe " + }, + { + 30, + L" Out-of-Band Remote Access " + }, + { + 31, + L" Boot Integrity Services (BIS) Entry Point" + }, + { + 32, + L" System Boot Information " + }, + { + 33, + L" 64-bit Memory Error Information " + }, + { + 34, + L" Management Device " + }, + { + 35, + L" Management Device Component " + }, + { + 36, + L" Management Device Threshold Data " + }, + { + 37, + L" Memory Channel " + }, + { + 38, + L" IPMI Device Information " + }, + { + 39, + L" System Power Supply" + }, + { + 40, + L" Additional Information" + }, + { + 41, + L" Onboard Devices Extended Information" + }, + { + 42, + L" Management Controller Host Interface" + }, + { + 43, + L" TPM Device" + }, + { + 44, + L" Processor Additional Information" + }, + { + 0x7E, + L" Inactive" + }, + { + 0x7F, + L" End-of-Table " + }, +}; + + +/** + Given a table and a Key, return the responding info. + + Notes: + Table[Index].Key is change from UINT8 to UINT16, + in order to deal with "0xaa - 0xbb". + + For example: + DisplaySELVariableDataFormatTypes(UINT8 Type, UINT8 Option) + has a item: + "0x07-0x7F, Unused" + Now define Key = 0x7F07, that is to say: High = 0x7F, Low = 0x07. + Then all the Key Value between Low and High gets the same string + L"Unused". + + @param[in] Table The begin address of table. + @param[in] Number The number of table items. + @param[in] Key The query Key. + @param[in, out] Info Input as empty buffer; output as data buffer. + @param[in] InfoLen The max number of characters for Info. + + @return the found Key and Info is valid. + @retval QUERY_TABLE_UNFOUND and Info should be NULL. +**/ +UINT8 +QueryTable ( + IN TABLE_ITEM *Table, + IN UINTN Number, + IN UINT8 Key, + IN OUT CHAR16 *Info, + IN UINTN InfoLen + ) +{ + UINTN Index; + // + // High byte and Low byte of word + // + UINT8 High; + UINT8 Low; + + for (Index = 0; Index < Number; Index++) { + High = (UINT8) (Table[Index].Key >> 8); + Low = (UINT8) (Table[Index].Key & 0x00FF); + + // + // Check if Key is in the range + // or if Key == Value in the table + // + if ((High > Low && Key >= Low && Key <= High) + || (Table[Index].Key == Key)) { + StrnCpyS (Info, InfoLen, Table[Index].Info, InfoLen - 1); + StrnCatS (Info, InfoLen, L"\n", InfoLen - 1 - StrLen(Info)); + return Key; + } + } + + StrCpyS (Info, InfoLen, L"Undefined Value\n"); + return QUERY_TABLE_UNFOUND; +} + +/** + Given a table of bit info and a Key, return the responding info to the Key. + + @param[in] Table Point to a table which maintains a map of 'bit' to 'message'. + @param[in] Number Number of table items. + @param[in] Bits The Key of query the bit map information. +**/ +VOID +PrintBitsInfo ( + IN TABLE_ITEM *Table, + IN UINTN Number, + IN UINT32 Bits + ) +{ + // + // Get certain bit of 'Value': + // +#define BIT(Value, bit) ((Value) & ((UINT32) 1) << (bit)) + // + // Clear certain bit of 'Value': + // +#define CLR_BIT(Value, bit) ((Value) -= (BIT (Value, bit))) + + UINTN Index; + UINT32 Value; + BOOLEAN FirstInfo; + + FirstInfo = TRUE; + Value = Bits; + // + // query the table and print information + // + for (Index = 0; Index < Number; Index++) { + if (BIT (Value, Table[Index].Key) != 0) { + if (!FirstInfo) { + // + // If it is not first info, print the separator first. + // + Print (L" | "); + } + Print (Table[Index].Info); + + FirstInfo = FALSE; + // + // clear the bit, for reserved bits test + // + CLR_BIT (Value, Table[Index].Key); + } + } + + // + // There is no any info if FirstInfo is still TRUE. + // + if (FirstInfo) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_NO_INFO), gShellDebug1HiiHandle); + } + + if (Value != 0) { + ShellPrintHiiEx(-1,-1,NULL, + STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_RSVD_BITS_SET), + gShellDebug1HiiHandle, + Value + ); + } + + Print (L"\n"); +} +// +// ////////////////////////////////////////////////////////////////// +// +// Following uses QueryTable functions to simplify the coding. +// QueryTable(), PrintBitsInfo() +// +// +#define PRINT_TABLE_ITEM(Table, Key) \ + do { \ + UINTN Num; \ + CHAR16 Info[66]; \ + Num = sizeof (Table) / sizeof (TABLE_ITEM); \ + ZeroMem (Info, sizeof (Info)); \ + QueryTable (Table, Num, Key, Info, sizeof(Info)/sizeof(Info[0])); \ + Print (Info); \ + } while (0); + +#define PRINT_BITS_INFO(Table, bits) \ + do { \ + UINTN Num; \ + Num = sizeof (Table) / sizeof (TABLE_ITEM); \ + PrintBitsInfo (Table, Num, (UINT32) bits); \ + } while (0); + +/** + Display System Information (Type 1) Type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySystemWakeupType ( + IN UINT8 Type, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_SYSTEM_WAKEUP_TYPE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Type, Option); + PRINT_TABLE_ITEM (SystemWakeupTypeTable, Type); +} + +/** + Display Base Board (Type 2) Feature Flags. + + @param[in] FeatureFlags The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayBaseBoardFeatureFlags ( + IN UINT8 FeatureFlags, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_BASE_BOARD_FEATURE_FLAGS), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (FeatureFlags, Option); + PRINT_BITS_INFO (BaseBoardFeatureFlagsTable, FeatureFlags); +} + +/** + Display Base Board (Type 2) Board Type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayBaseBoardBoardType( + IN UINT8 Type, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_BASE_BOARD_BOARD_TYPE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Type, Option); + PRINT_TABLE_ITEM (BaseBoardBoardTypeTable, Type); +} + +/** + Display System Enclosure (Type 3) Enclosure Type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySystemEnclosureType ( + IN UINT8 Type, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_SYSTEM_CHASSIS_TYPE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Type, Option); + // + // query table and print info + // + PRINT_TABLE_ITEM (SystemEnclosureTypeTable, Type); + + if (BIT (Type, 7) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_CHASSIS_LOCK_PRESENT), gShellDebug1HiiHandle); + } +} + +/** + Display System Enclosure (Type 3) Enclosure Status. + + @param[in] Status The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySystemEnclosureStatus ( + IN UINT8 Status, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_SYSTEM_CHASSIS_STATUS), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Status, Option); + PRINT_TABLE_ITEM (SystemEnclosureStatusTable, Status); +} + +/** + Display System Enclosure (Type 3) Security Status. + + @param[in] Status The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySESecurityStatus ( + IN UINT8 Status, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_SYSTEM_CHASSIS_SECURITY), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Status, Option); + PRINT_TABLE_ITEM (SESecurityStatusTable, Status); +} + +/** + Display Processor Information (Type 4) Type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayProcessorType ( + IN UINT8 Type, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_PROC_TYPE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Type, Option); + PRINT_TABLE_ITEM (ProcessorTypeTable, Type); +} + +/** + Display Processor Information (Type 4) Upgrade. + + @param[in] Upgrade The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayProcessorUpgrade ( + IN UINT8 Upgrade, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_PROC_UPDATE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Upgrade, Option); + PRINT_TABLE_ITEM (ProcessorUpgradeTable, Upgrade); +} + +/** + Display Processor Information (Type 4) Characteristics. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayProcessorCharacteristics ( + IN UINT16 Type, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_PROC_CHARACTERISTICS), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Type, Option); + PRINT_BITS_INFO (ProcessorCharacteristicsTable, Type); +} + +/** + Display Memory Controller Information (Type 5) method. + + @param[in] Method The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMcErrorDetectMethod ( + IN UINT8 Method, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_MEM_DETECTMETHOD), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Method, Option); + PRINT_TABLE_ITEM (McErrorDetectMethodTable, Method); +} + +/** + Display Memory Controller Information (Type 5) Capability. + + @param[in] Capability The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMcErrorCorrectCapability ( + IN UINT8 Capability, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_MEM_CORRECT_CAPABILITY), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Capability, Option); + PRINT_BITS_INFO (McErrorCorrectCapabilityTable, Capability); +} + +/** + Display Memory Controller Information (Type 5) Support. + + @param[in] Support The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMcInterleaveSupport ( + IN UINT8 Support, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_MEM_INTERLEAVE_SUPPORT), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Support, Option); + PRINT_TABLE_ITEM (McInterleaveSupportTable, Support); +} + +/** + Display Memory Controller Information (Type 5) speeds. + + @param[in] Speed The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMcMemorySpeeds ( + IN UINT16 Speed, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_MEM_MEMORY_SPEED), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Speed, Option); + PRINT_BITS_INFO (McMemorySpeedsTable, Speed); +} + +/** + Display Memory Controller Information (Type 5) voltage. + + @param[in] Voltage The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMemoryModuleVoltage ( + IN UINT8 Voltage, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_REQUIRED_VOLTAGES), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Voltage, Option); + PRINT_BITS_INFO (MemoryModuleVoltageTable, Voltage); +} + +/** + Display Memory Module Information (Type 6) type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMmMemoryType ( + IN UINT16 Type, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_MEM_MODULE_TYPE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Type, Option); + PRINT_BITS_INFO (MmMemoryTypeTable, Type); +} + +/** + Display Memory Module Information (Type 6) status. + + @param[in] Status The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMmErrorStatus ( + IN UINT8 Status, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_MEM_MODULE_ERROR_STATUS), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Status, Option); + PRINT_BITS_INFO (MmErrorStatusTable, Status); +} + +/** + Display Cache Information (Type 7) SRAM Type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayCacheSRAMType ( + IN UINT16 Type, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_CACHE_SRAM_TYPE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION ((UINT8) Type, Option); + PRINT_BITS_INFO (CacheSRAMTypeTable, (UINT8) Type); +} + +/** + Display Cache Information (Type 7) correcting Type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayCacheErrCorrectingType ( + IN UINT8 Type, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_CACHE_ERROR_CORRECTING), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Type, Option); + PRINT_TABLE_ITEM (CacheErrCorrectingTypeTable, Type); +} + +/** + Display Cache Information (Type 7) Type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayCacheSystemCacheType ( + IN UINT8 Type, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_CACHE_SYSTEM_TYPE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Type, Option); + PRINT_TABLE_ITEM (CacheSystemCacheTypeTable, Type); +} + +/** + Display Cache Information (Type 7) Associativity. + + @param[in] Associativity The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayCacheAssociativity ( + IN UINT8 Associativity, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_CACHE_ASSOCIATIVITY), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Associativity, Option); + PRINT_TABLE_ITEM (CacheAssociativityTable, Associativity); +} + +/** + Display Port Connector Information (Type 8) type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayPortConnectorType ( + IN UINT8 Type, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_PORT_CONNECTOR_TYPE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Type, Option); + PRINT_TABLE_ITEM (PortConnectorTypeTable, Type); +} + +/** + Display Port Connector Information (Type 8) port type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayPortType ( + IN UINT8 Type, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_PORT_TYPE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Type, Option); + PRINT_TABLE_ITEM (PortTypeTable, Type); +} + +/** + Display System Slots (Type 9) slot type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySystemSlotType ( + IN UINT8 Type, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_SYSTEM_SLOT_TYPE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Type, Option); + PRINT_TABLE_ITEM (SystemSlotTypeTable, Type); +} + +/** + Display System Slots (Type 9) data bus width. + + @param[in] Width The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySystemSlotDataBusWidth ( + IN UINT8 Width, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_SYSTEM_SLOT_DATA), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Width, Option); + PRINT_TABLE_ITEM (SystemSlotDataBusWidthTable, Width); +} + +/** + Display System Slots (Type 9) usage information. + + @param[in] Usage The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySystemSlotCurrentUsage ( + IN UINT8 Usage, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_SYSTEM_SLOT_CURRENT_USAGE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Usage, Option); + PRINT_TABLE_ITEM (SystemSlotCurrentUsageTable, Usage); +} + +/** + Display System Slots (Type 9) slot length. + + @param[in] Length The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySystemSlotLength ( + IN UINT8 Length, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_SYSTEM_SLOT_LENGTH), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Length, Option); + PRINT_TABLE_ITEM (SystemSlotLengthTable, Length); +} + +/** + Display System Slots (Type 9) characteristics. + + @param[in] Chara1 The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySlotCharacteristics1 ( + IN UINT8 Chara1, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_SLOT_CHARACTERISTICS), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Chara1, Option); + PRINT_BITS_INFO (SlotCharacteristics1Table, Chara1); +} + +/** + Display System Slots (Type 9) characteristics. + + @param[in] Chara2 The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySlotCharacteristics2 ( + IN UINT8 Chara2, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_SLOT_CHARACTERISTICS_2), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Chara2, Option); + PRINT_BITS_INFO (SlotCharacteristics2Table, Chara2); +} + +/** + Display On Board Devices Information (Type 10) types. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayOnboardDeviceTypes ( + IN UINT8 Type, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_ONBOARD_DEVICE_TYPE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Type, Option); + PRINT_TABLE_ITEM (OnboardDeviceTypesTable, Type); +} + +/** + Display System Event Log (Type 15) types. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySELTypes ( + IN UINT8 Type, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_SYSTEM_EVENT_LOG_TYPE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Type, Option); + PRINT_TABLE_ITEM (SELTypesTable, Type); +} + +/** + Display System Event Log (Type 15) format type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySELVarDataFormatType ( + IN UINT8 Type, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_EVENT_LOG_VAR_DATA_FORMAT), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Type, Option); + PRINT_TABLE_ITEM (SELVarDataFormatTypeTable, Type); +} + +/** + Display System Event Log (Type 15) dw1. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayPostResultsBitmapDw1 ( + IN UINT32 Key, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_POST_RESULTS_BITMAP), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Key, Option); + PRINT_BITS_INFO (PostResultsBitmapDw1Table, Key); +} + +/** + Display System Event Log (Type 15) dw2. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayPostResultsBitmapDw2 ( + IN UINT32 Key, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_POST_RESULTS_SECOND_DWORD), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Key, Option); + PRINT_BITS_INFO (PostResultsBitmapDw2Table, Key); +} + +/** + Display System Event Log (Type 15) type. + + @param[in] SMType The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySELSysManagementTypes ( + IN UINT32 SMType, + IN UINT8 Option + ) +{ + UINT8 Temp; + + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_SYSTEM_MANAGEMENT_TYPES), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (SMType, Option); + + // + // Deal with wide range Value + // + if (SMType >= 0x80000000) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_OEM_ASSIGNED), gShellDebug1HiiHandle); + } else if (SMType >= 0x00020000) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_RSVD_FOR_FUTURE_ASSIGN), gShellDebug1HiiHandle); + } else if (SMType >= 0x00010000) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_SYSTEM_MANAGEMENT_PROBE), gShellDebug1HiiHandle); + } else if (SMType >= 0x31) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_RSVD_FOR_FUTURE_ASSIGN), gShellDebug1HiiHandle); + } else { + // + // Deal with One byte data + // + Temp = (UINT8) (SMType & 0x3F); + PRINT_TABLE_ITEM (SELSysManagementTypesTable, Temp); + } +} + +/** + Display Physical Memory Array (Type 16) Location. + + @param[in] Location The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayPMALocation ( + IN UINT8 Location, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_PHYS_MEM_ARRAY_LOCATION), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Location, Option); + PRINT_TABLE_ITEM (PMALocationTable, Location); +} + +/** + Display Physical Memory Array (Type 16) Use. + + @param[in] Use The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayPMAUse ( + IN UINT8 Use, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_PHYS_MEM_ARRAY_USE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Use, Option); + PRINT_TABLE_ITEM (PMAUseTable, Use); +} + +/** + Display Physical Memory Array (Type 16) Types. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayPMAErrorCorrectionTypes ( + IN UINT8 Type, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_PHYS_MEM_ARRAY_ERROR), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Type, Option); + PRINT_TABLE_ITEM (PMAErrorCorrectionTypesTable, Type); +} + +/** + Display Memory Device (Type 17) form factor. + + @param[in] FormFactor The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMemoryDeviceFormFactor ( + IN UINT8 FormFactor, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_MEM_DEVICE_FORM_FACTOR), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (FormFactor, Option); + PRINT_TABLE_ITEM (MemoryDeviceFormFactorTable, FormFactor); +} + +/** + Display Memory Device (Type 17) type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMemoryDeviceType ( + IN UINT8 Type, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_MEM_DEVICE_TYPE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Type, Option); + PRINT_TABLE_ITEM (MemoryDeviceTypeTable, Type); +} + +/** + Display Memory Device (Type 17) details. + + @param[in] Para The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMemoryDeviceTypeDetail ( + IN UINT16 Para, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_MEM_DEVICE_TYPE_DETAIL), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Para, Option); + PRINT_BITS_INFO (MemoryDeviceTypeDetailTable, Para); +} + +/** + Display Memory Device (Type 17) memory technology. + + @param[in] Para The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMemoryDeviceMemoryTechnology ( + IN UINT8 Para, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_MEM_DEVICE_MEMORY_TECHNOLOGY), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Para, Option); + PRINT_TABLE_ITEM (MemoryDeviceMemoryTechnologyTable, Para); +} + +/** + Display Memory Device (Type 17) memory operating mode capability. + + @param[in] Para The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMemoryDeviceMemoryOperatingModeCapability ( + IN UINT16 Para, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_MEM_DEVICE_MEM_OPER_MODE_CAPA), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Para, Option); + PRINT_BITS_INFO (MemoryDeviceMemoryOperatingModeCapabilityTable, Para); +} + +/** + Display 32-bit Memory Error Information (Type 18) type. + + @param[in] ErrorType The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMemoryErrorType ( + IN UINT8 ErrorType, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_MEM_ERROR_INFO), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (ErrorType, Option); + PRINT_TABLE_ITEM (MemoryErrorTypeTable, ErrorType); +} + +/** + Display 32-bit Memory Error Information (Type 18) error granularity. + + @param[in] Granularity The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMemoryErrorGranularity ( + IN UINT8 Granularity, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_MEM_ERROR_GRANULARITY), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Granularity, Option); + PRINT_TABLE_ITEM (MemoryErrorGranularityTable, Granularity); +} + +/** + Display 32-bit Memory Error Information (Type 18) error information. + + @param[in] Operation The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMemoryErrorOperation ( + IN UINT8 Operation, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_MEM_ERROR_OP), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Operation, Option); + PRINT_TABLE_ITEM (MemoryErrorOperationTable, Operation); +} + +/** + Display Built-in Pointing Device (Type 21) type information. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayPointingDeviceType ( + IN UINT8 Type, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_POINTING_DEVICE_TYPE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Type, Option); + PRINT_TABLE_ITEM (PointingDeviceTypeTable, Type); +} + +/** + Display Built-in Pointing Device (Type 21) information. + + @param[in] Interface The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayPointingDeviceInterface ( + IN UINT8 Interface, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_POINTING_DEVICE_INTERFACE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Interface, Option); + PRINT_TABLE_ITEM (PointingDeviceInterfaceTable, Interface); +} + +/** + Display Portable Battery (Type 22) information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayPBDeviceChemistry ( + IN UINT8 Key, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_PORTABLE_BATT_DEV_CHEM), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Key, Option); + PRINT_TABLE_ITEM (PBDeviceChemistryTable, Key); +} + +/** + Display Voltage Probe (Type 26) location information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayVPLocation ( + IN UINT8 Key, + IN UINT8 Option + ) +{ + UINT8 Loc; + + Loc = (UINT8) ((Key & 0xE0) >> 5); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_VOLTAGE_PROBE_LOC), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Loc, Option); + PRINT_TABLE_ITEM (VPLocationTable, Loc); +} + +/** + Display Voltage Probe (Type 26) status ype information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayVPStatus ( + IN UINT8 Key, + IN UINT8 Option + ) +{ + UINT8 Status; + + Status = (UINT8) (Key & 0x1F); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_VOLTAGE_PROBE_STATUS), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Status, Option); + PRINT_TABLE_ITEM (VPStatusTable, Status); +} + +/** + Display Cooling (Type 27) status information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayCoolingDeviceStatus ( + IN UINT8 Key, + IN UINT8 Option + ) +{ + UINT8 Status; + + Status = (UINT8) ((Key & 0xE0) >> 5); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_COOLING_DEV_STATUS), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Status, Option); + PRINT_TABLE_ITEM (CoolingDeviceStatusTable, Status); +} + +/** + Display Cooling (Type 27) type information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayCoolingDeviceType ( + IN UINT8 Key, + IN UINT8 Option + ) +{ + UINT8 Type; + + Type = (UINT8) (Key & 0x1F); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_COOLING_DEV_TYPE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Type, Option); + PRINT_TABLE_ITEM (CoolingDeviceTypeTable, Type); +} + +/** + Display Temperature Probe (Type 28) status information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayTemperatureProbeStatus ( + IN UINT8 Key, + IN UINT8 Option + ) +{ + UINT8 Status; + + Status = (UINT8) ((Key & 0xE0) >> 5); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_TEMP_PROBE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Status, Option); + PRINT_TABLE_ITEM (TemperatureProbeStatusTable, Status); +} + +/** + Display Temperature Probe (Type 28) location information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayTemperatureProbeLoc ( + IN UINT8 Key, + IN UINT8 Option + ) +{ + UINT8 Loc; + + Loc = (UINT8) (Key & 0x1F); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_VOLTAGE_PROBE_LOC), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Loc, Option); + PRINT_TABLE_ITEM (TemperatureProbeLocTable, Loc); +} + +/** + Display Electrical Current Probe (Type 29) status information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayECPStatus ( + IN UINT8 Key, + IN UINT8 Option + ) +{ + UINT8 Status; + + Status = (UINT8) ((Key & 0xE0) >> 5); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_ELEC_PROBE_STATUS), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Status, Option); + PRINT_TABLE_ITEM (ECPStatusTable, Status); +} + +/** + Display Type 29 information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayECPLoc ( + IN UINT8 Key, + IN UINT8 Option + ) +{ + UINT8 Loc; + + Loc = (UINT8) (Key & 0x1F); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_ELEC_PROBE_LOC), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Loc, Option); + PRINT_TABLE_ITEM (ECPLocTable, Loc); +} + +/** + Display Management Device (Type 34) Type. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMDType ( + IN UINT8 Key, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_MANAGEMENT_DEV_TYPE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Key, Option); + PRINT_TABLE_ITEM (MDTypeTable, Key); +} + +/** + Display Management Device (Type 34) Address Type. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMDAddressType ( + IN UINT8 Key, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_MANAGEMENT_DEV_ADDR_TYPE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Key, Option); + PRINT_TABLE_ITEM (MDAddressTypeTable, Key); +} + +/** + Display Memory Channel (Type 37) information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMemoryChannelType ( + IN UINT8 Key, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_MEM_CHANNEL_TYPE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Key, Option); + PRINT_TABLE_ITEM (MemoryChannelTypeTable, Key); +} + +/** + Display IPMI Device Information (Type 38) information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayIPMIDIBMCInterfaceType ( + IN UINT8 Key, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_BMC_INTERFACE_TYPE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Key, Option); + PRINT_TABLE_ITEM (IPMIDIBMCInterfaceTypeTable, Key); +} + +/** + Display Management Controller Host Interface (Type 42) information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMCHostInterfaceType ( + IN UINT8 Key, + IN UINT8 Option + ) +{ + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_MC_HOST_INTERFACE_TYPE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Key, Option); + PRINT_TABLE_ITEM (MCHostInterfaceTypeTable, Key); +} + +/** + Display Processor Architecture Type (Type 44). + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayProcessorArchitectureType ( + IN UINT8 Key, + IN UINT8 Option + ) +{ + ShellPrintHiiEx (-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_PROCESSOR_ARCH_TYPE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Key, Option); + PRINT_TABLE_ITEM (ProcessorArchitectureTypesTable, Key); +} + +/** + Display the structure type information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayStructureTypeInfo ( + IN UINT8 Key, + IN UINT8 Option + ) +{ + // + // display + // + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_QUERYTABLE_STRUCT_TYPE), gShellDebug1HiiHandle); + PRINT_INFO_OPTION (Key, Option); + PRINT_TABLE_ITEM (StructureTypeInfoTable, Key); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/QueryTable.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/QueryTable.h new file mode 100644 index 00000000..6bc0c26f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/QueryTable.h @@ -0,0 +1,814 @@ +/** @file + Build a table, each item is (key, info) pair. + and give a interface of query a string out of a table. + + Copyright (c) 2005 - 2019, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SMBIOS_QUERY_TABLE_H_ +#define _SMBIOS_QUERY_TABLE_H_ + +#include + +#define QUERY_TABLE_UNFOUND 0xFF + +typedef struct TABLE_ITEM { + UINT16 Key; + CHAR16 *Info; +} TABLE_ITEM; + +// +// Print info by option +// +#define PRINT_INFO_OPTION(Value, Option) \ + do { \ + if (Option == SHOW_NONE) { \ + return ; \ + } \ + if (Option < SHOW_DETAIL) { \ + Print (L"0x%x\n", Value); \ + return ; \ + } \ + } while (0); + +/** + Given a table and a Key, return the responding info. + + Notes: + Table[Index].Key is change from UINT8 to UINT16, + in order to deal with "0xaa - 0xbb". + + For example: + DisplaySELVariableDataFormatTypes(UINT8 Type, UINT8 Option) + has a item: + "0x07-0x7F, Unused" + Now define Key = 0x7F07, that is to say: High = 0x7F, Low = 0x07. + Then all the Key Value between Low and High gets the same string + L"Unused". + + @param[in] Table The begin address of table. + @param[in] Number The number of table items. + @param[in] Key The query Key. + @param[in, out] Info Input as empty buffer; output as data buffer. + @param[in] InfoLen The max number of characters for Info. + + @return the found Key and Info is valid. + @retval QUERY_TABLE_UNFOUND and Info should be NULL. +**/ +UINT8 +QueryTable ( + IN TABLE_ITEM *Table, + IN UINTN Number, + IN UINT8 Key, + IN OUT CHAR16 *Info, + IN UINTN InfoLen + ); + +/** + Display the structure type information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayStructureTypeInfo ( + IN UINT8 Key, + IN UINT8 Option + ); + +/** + Display System Information (Type 1) Type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySystemWakeupType ( + IN UINT8 Type, + IN UINT8 Option + ); + +/** + Display Base Board (Type 2) Feature Flags. + + @param[in] FeatureFlags The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayBaseBoardFeatureFlags ( + IN UINT8 FeatureFlags, + IN UINT8 Option + ); + +/** + Display Base Board (Type 2) Board Type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayBaseBoardBoardType( + IN UINT8 Type, + IN UINT8 Option + ); + +/** + Display System Enclosure (Type 3) Enclosure Type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySystemEnclosureType ( + IN UINT8 Type, + IN UINT8 Option + ); + +/** + Display System Enclosure (Type 3) Enclosure Status. + + @param[in] Status The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySystemEnclosureStatus ( + IN UINT8 Status, + IN UINT8 Option + ); + +/** + Display System Enclosure (Type 3) Security Status. + + @param[in] Status The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySESecurityStatus ( + IN UINT8 Status, + IN UINT8 Option + ) +; + +/** + Display Processor Information (Type 4) Type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayProcessorType ( + IN UINT8 Type, + IN UINT8 Option + ); + +/** + Display Processor Information (Type 4) Upgrade. + + @param[in] Upgrade The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayProcessorUpgrade ( + IN UINT8 Upgrade, + IN UINT8 Option + ); + +/** + Display Processor Information (Type 4) Characteristics. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayProcessorCharacteristics ( + IN UINT16 Type, + IN UINT8 Option + ); + +/** + Display Memory Controller Information (Type 5) method. + + @param[in] Method The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMcErrorDetectMethod ( + IN UINT8 Method, + IN UINT8 Option + ); + +/** + Display Memory Controller Information (Type 5) Capability. + + @param[in] Capability The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMcErrorCorrectCapability ( + IN UINT8 Capability, + IN UINT8 Option + ); + +/** + Display Memory Controller Information (Type 5) Support. + + @param[in] Support The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMcInterleaveSupport ( + IN UINT8 Support, + IN UINT8 Option + ); + +/** + Display Memory Controller Information (Type 5) speeds. + + @param[in] Speed The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMcMemorySpeeds ( + IN UINT16 Speed, + IN UINT8 Option + ); + +/** + Display Memory Controller Information (Type 5) voltage. + + @param[in] Voltage The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMemoryModuleVoltage ( + IN UINT8 Voltage, + IN UINT8 Option + ); + +/** + Display Memory Module Information (Type 6) type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMmMemoryType ( + IN UINT16 Type, + IN UINT8 Option + ); + +/** + Display Memory Module Information (Type 6) status. + + @param[in] Status The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMmErrorStatus ( + IN UINT8 Status, + IN UINT8 Option + ); + +/** + Display Cache Information (Type 7) SRAM Type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayCacheSRAMType ( + IN UINT16 Type, + IN UINT8 Option + ); + +/** + Display Cache Information (Type 7) correcting Type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayCacheErrCorrectingType ( + IN UINT8 Type, + IN UINT8 Option + ); + +/** + Display Cache Information (Type 7) Type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayCacheSystemCacheType ( + IN UINT8 Type, + IN UINT8 Option + ); + +/** + Display Cache Information (Type 7) Associativity. + + @param[in] Associativity The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayCacheAssociativity ( + IN UINT8 Associativity, + IN UINT8 Option + ); + +/** + Display Port Connector Information (Type 8) type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayPortConnectorType ( + IN UINT8 Type, + IN UINT8 Option + ); + +/** + Display Port Connector Information (Type 8) port type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayPortType ( + IN UINT8 Type, + IN UINT8 Option + ); + +/** + Display System Slots (Type 9) slot type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySystemSlotType ( + IN UINT8 Type, + IN UINT8 Option + ); + +/** + Display System Slots (Type 9) data bus width. + + @param[in] Width The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySystemSlotDataBusWidth ( + IN UINT8 Width, + IN UINT8 Option + ); + +/** + Display System Slots (Type 9) usage information. + + @param[in] Usage The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySystemSlotCurrentUsage ( + IN UINT8 Usage, + IN UINT8 Option + ); + +/** + Display System Slots (Type 9) slot length. + + @param[in] Length The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySystemSlotLength ( + IN UINT8 Length, + IN UINT8 Option + ); + +/** + Display System Slots (Type 9) characteristics. + + @param[in] Chara1 The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySlotCharacteristics1 ( + IN UINT8 Chara1, + IN UINT8 Option + ); + +/** + Display System Slots (Type 9) characteristics. + + @param[in] Chara2 The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySlotCharacteristics2 ( + IN UINT8 Chara2, + IN UINT8 Option + ); + +/** + Display On Board Devices Information (Type 10) types. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayOnboardDeviceTypes ( + IN UINT8 Type, + IN UINT8 Option + ); + +/** + Display System Event Log (Type 15) types. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySELTypes ( + IN UINT8 Type, + IN UINT8 Option + ); + +/** + Display System Event Log (Type 15) format type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySELVarDataFormatType ( + IN UINT8 Type, + IN UINT8 Option + ); + +/** + Display System Event Log (Type 15) dw1. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayPostResultsBitmapDw1 ( + IN UINT32 Key, + IN UINT8 Option + ); + +/** + Display System Event Log (Type 15) dw2. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayPostResultsBitmapDw2 ( + IN UINT32 Key, + IN UINT8 Option + ); + +/** + Display System Event Log (Type 15) type. + + @param[in] SMType The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplaySELSysManagementTypes ( + IN UINT32 SMType, + IN UINT8 Option + ); + +/** + Display Physical Memory Array (Type 16) Location. + + @param[in] Location The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayPMALocation ( + IN UINT8 Location, + IN UINT8 Option + ); + +/** + Display Physical Memory Array (Type 16) Use. + + @param[in] Use The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayPMAUse ( + IN UINT8 Use, + IN UINT8 Option + ); + +/** + Display Physical Memory Array (Type 16) Types. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayPMAErrorCorrectionTypes ( + IN UINT8 Type, + IN UINT8 Option + ); + +/** + Display Memory Device (Type 17) form factor. + + @param[in] FormFactor The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMemoryDeviceFormFactor ( + IN UINT8 FormFactor, + IN UINT8 Option + ); + +/** + Display Memory Device (Type 17) type. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMemoryDeviceType ( + IN UINT8 Type, + IN UINT8 Option + ); + +/** + Display Memory Device (Type 17) details. + + @param[in] Para The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMemoryDeviceTypeDetail ( + IN UINT16 Para, + IN UINT8 Option + ); + +/** + Display Memory Device (Type 17) memory technology. + + @param[in] Para The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMemoryDeviceMemoryTechnology ( + IN UINT8 Para, + IN UINT8 Option + ); + +/** + Display Memory Device (Type 17) memory operating mode capability. + + @param[in] Para The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMemoryDeviceMemoryOperatingModeCapability ( + IN UINT16 Para, + IN UINT8 Option + ); + +/** + Display 32-bit Memory Error Information (Type 18) type. + + @param[in] ErrorType The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMemoryErrorType ( + IN UINT8 ErrorType, + IN UINT8 Option + ); + +/** + Display 32-bit Memory Error Information (Type 18) error granularity. + + @param[in] Granularity The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMemoryErrorGranularity ( + IN UINT8 Granularity, + IN UINT8 Option + ); + +/** + Display 32-bit Memory Error Information (Type 18) error information. + + @param[in] Operation The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMemoryErrorOperation ( + IN UINT8 Operation, + IN UINT8 Option + ); + +/** + Display Built-in Pointing Device (Type 21) type information. + + @param[in] Type The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayPointingDeviceType ( + IN UINT8 Type, + IN UINT8 Option + ); + +/** + Display Built-in Pointing Device (Type 21) information. + + @param[in] Interface The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayPointingDeviceInterface ( + IN UINT8 Interface, + IN UINT8 Option + ); + +/** + Display Portable Battery (Type 22) information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayPBDeviceChemistry ( + IN UINT8 Key, + IN UINT8 Option + ); + +/** + Display Voltage Probe (Type 26) location information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayVPLocation ( + IN UINT8 Key, + IN UINT8 Option + ); + +/** + Display Voltage Probe (Type 26) status ype information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayVPStatus ( + IN UINT8 Key, + IN UINT8 Option + ); + +/** + Display Cooling (Type 27) status information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayCoolingDeviceStatus ( + IN UINT8 Key, + IN UINT8 Option + ); + +/** + Display Cooling (Type 27) type information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayCoolingDeviceType ( + IN UINT8 Key, + IN UINT8 Option + ); + +/** + Display Temperature Probe (Type 28) status information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayTemperatureProbeStatus ( + IN UINT8 Key, + IN UINT8 Option + ); + +/** + Display Temperature Probe (Type 28) location information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayTemperatureProbeLoc ( + IN UINT8 Key, + IN UINT8 Option + ); + +/** + Display Electrical Current Probe (Type 29) status information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayECPStatus ( + IN UINT8 Key, + IN UINT8 Option + ); + +/** + Display Electrical Current Probe (Type 29) location information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayECPLoc ( + IN UINT8 Key, + IN UINT8 Option + ); + +/** + Display Management Device (Type 34) Type. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMDType ( + IN UINT8 Key, + IN UINT8 Option + ); + +/** + Display Management Device (Type 34) Address Type. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMDAddressType ( + IN UINT8 Key, + IN UINT8 Option + ); + +/** + Display Memory Channel (Type 37) information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMemoryChannelType ( + IN UINT8 Key, + IN UINT8 Option + ); + +/** + Display IPMI Device Information (Type 38) information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayIPMIDIBMCInterfaceType ( + IN UINT8 Key, + IN UINT8 Option + ); + +/** + Display Management Controller Host Interface (Type 42) information. + + @param[in] Key The key of the structure. + @param[in] Option The optional information. +**/ +VOID +DisplayMCHostInterfaceType ( + IN UINT8 Key, + IN UINT8 Option + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/SmbiosView.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/SmbiosView.c new file mode 100644 index 00000000..bba5421f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/SmbiosView.c @@ -0,0 +1,999 @@ +/** @file + Tools of clarify the content of the smbios table. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDebug1CommandsLib.h" +#include "LibSmbiosView.h" +#include "SmbiosView.h" +#include "PrintInfo.h" +#include "QueryTable.h" + +UINT8 gShowType = SHOW_DETAIL; +STATIC STRUCTURE_STATISTICS *mStatisticsTable = NULL; +STATIC STRUCTURE_STATISTICS *mSmbios64BitStatisticsTable = NULL; + +UINT8 SmbiosMajorVersion; +UINT8 SmbiosMinorVersion; + +UINTN mNumberOfSmbios64BitStructures; +UINTN mSmbios64BitTableLength; + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-t", TypeValue}, + {L"-h", TypeValue}, + {L"-s", TypeFlag}, + {L"-a", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'smbiosview' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunSmbiosView ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + UINT8 StructType; + UINT16 StructHandle; + EFI_STATUS Status; + EFI_STATUS Status1; + EFI_STATUS Status2; + BOOLEAN RandomView; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CONST CHAR16 *Temp; + + mStatisticsTable = NULL; + mSmbios64BitStatisticsTable = NULL; + Package = NULL; + ShellStatus = SHELL_SUCCESS; + + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"smbiosview", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetCount(Package) > 1) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"smbiosview"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetFlag(Package, L"-t") && ShellCommandLineGetValue(Package, L"-t") == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDebug1HiiHandle, L"smbiosview", L"-t"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetFlag(Package, L"-h") && ShellCommandLineGetValue(Package, L"-h") == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDebug1HiiHandle, L"smbiosview", L"-h"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if ( + (ShellCommandLineGetFlag(Package, L"-t") && ShellCommandLineGetFlag(Package, L"-h")) || + (ShellCommandLineGetFlag(Package, L"-t") && ShellCommandLineGetFlag(Package, L"-s")) || + (ShellCommandLineGetFlag(Package, L"-t") && ShellCommandLineGetFlag(Package, L"-a")) || + (ShellCommandLineGetFlag(Package, L"-h") && ShellCommandLineGetFlag(Package, L"-s")) || + (ShellCommandLineGetFlag(Package, L"-h") && ShellCommandLineGetFlag(Package, L"-a")) || + (ShellCommandLineGetFlag(Package, L"-s") && ShellCommandLineGetFlag(Package, L"-a")) + ) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"smbiosview"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + + // + // Init Lib + // + Status1 = LibSmbiosInit (); + Status2 = LibSmbios64BitInit (); + if (EFI_ERROR (Status1) && EFI_ERROR (Status2)) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_LIBSMBIOSVIEW_CANNOT_GET_TABLE), gShellDebug1HiiHandle); + ShellStatus = SHELL_NOT_FOUND; + goto Done; + } + + StructType = STRUCTURE_TYPE_RANDOM; + RandomView = TRUE; + + Temp = ShellCommandLineGetValue(Package, L"-t"); + if (Temp != NULL) { + StructType = (UINT8) ShellStrToUintn (Temp); + } + + if (ShellCommandLineGetFlag(Package, L"-a")) { + gShowType = SHOW_ALL; + } + + if (!EFI_ERROR (Status1)) { + // + // Initialize the StructHandle to be the first handle + // + StructHandle = INVALID_HANDLE; + LibGetSmbiosStructure (&StructHandle, NULL, NULL); + + Temp = ShellCommandLineGetValue(Package, L"-h"); + if (Temp != NULL) { + RandomView = FALSE; + StructHandle = (UINT16) ShellStrToUintn(Temp); + } + // + // build statistics table + // + Status = InitSmbiosTableStatistics (); + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_NOT_FOUND; + goto Done; + } + + if (ShellCommandLineGetFlag(Package, L"-s")) { + Status = DisplayStatisticsTable (SHOW_DETAIL); + if (EFI_ERROR(Status)) { + ShellStatus = SHELL_NOT_FOUND; + } + goto Show64Bit; + } + + // + // Show SMBIOS structure information + // + Status = SMBiosView (StructType, StructHandle, gShowType, RandomView); + if (EFI_ERROR(Status)) { + ShellStatus = SHELL_NOT_FOUND; + goto Done; + } + } + +Show64Bit: + if (!EFI_ERROR (Status2)) { + // + // build statistics table + // + Status = InitSmbios64BitTableStatistics (); + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_NOT_FOUND; + goto Done; + } + // + // Initialize the StructHandle to be the first handle + // + StructHandle = INVALID_HANDLE; + LibGetSmbios64BitStructure (&StructHandle, NULL, NULL); + + Temp = ShellCommandLineGetValue(Package, L"-h"); + if (Temp != NULL) { + RandomView = FALSE; + StructHandle = (UINT16) ShellStrToUintn(Temp); + } + + if (ShellCommandLineGetFlag(Package, L"-s")) { + Status = DisplaySmbios64BitStatisticsTable (SHOW_DETAIL); + if (EFI_ERROR(Status)) { + ShellStatus = SHELL_NOT_FOUND; + } + goto Done; + } + + // + // Show SMBIOS structure information + // + Status = SMBios64View (StructType, StructHandle, gShowType, RandomView); + if (EFI_ERROR(Status)) { + ShellStatus = SHELL_NOT_FOUND; + } + } + } + } +Done: + // + // Release resources + // + if (mStatisticsTable != NULL) { + // + // Release statistics table + // + FreePool (mStatisticsTable); + mStatisticsTable = NULL; + } + + if (mSmbios64BitStatisticsTable != NULL) { + // + // Release statistics table + // + FreePool (mSmbios64BitStatisticsTable); + mSmbios64BitStatisticsTable = NULL; + } + + if (Package != NULL) { + ShellCommandLineFreeVarList (Package); + } + + LibSmbiosCleanup (); + LibSmbios64BitCleanup (); + + return ShellStatus; +} + +/** + Query all structures Data from SMBIOS table and Display + the information to users as required display option. + + @param[in] QueryType Structure type to view. + @param[in] QueryHandle Structure handle to view. + @param[in] Option Display option: none,outline,normal,detail. + @param[in] RandomView Support for -h parameter. + + @retval EFI_SUCCESS print is successful. + @retval EFI_BAD_BUFFER_SIZE structure is out of the range of SMBIOS table. +**/ +EFI_STATUS +SMBiosView ( + IN UINT8 QueryType, + IN UINT16 QueryHandle, + IN UINT8 Option, + IN BOOLEAN RandomView + ) +{ + UINT16 Handle; + UINT8 *Buffer; + UINT16 Length; + UINTN Index; + + SMBIOS_STRUCTURE_POINTER SmbiosStruct; + SMBIOS_TABLE_ENTRY_POINT *SMBiosTable; + + SMBiosTable = NULL; + LibSmbiosGetEPS (&SMBiosTable); + if (SMBiosTable == NULL) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_CANNOT_ACCESS_TABLE), gShellDebug1HiiHandle); + return EFI_BAD_BUFFER_SIZE; + } + + if (CompareMem (SMBiosTable->AnchorString, "_SM_", 4) == 0) { + // + // Have got SMBIOS table + // + SmbiosPrintEPSInfo (SMBiosTable, Option); + + SmbiosMajorVersion = SMBiosTable->MajorVersion; + SmbiosMinorVersion = SMBiosTable->MinorVersion; + + ShellPrintEx(-1,-1,L"=========================================================\n"); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_QUERY_STRUCT_COND), gShellDebug1HiiHandle); + + if (QueryType == STRUCTURE_TYPE_RANDOM) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_QUERYTYPE_RANDOM), gShellDebug1HiiHandle); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_QUERYTYPE), gShellDebug1HiiHandle, QueryType); + } + + if (RandomView) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_QUERYHANDLE_RANDOM), gShellDebug1HiiHandle); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_QUERYHANDLE), gShellDebug1HiiHandle, QueryHandle); + } + + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_SHOWTYPE), gShellDebug1HiiHandle); + ShellPrintEx(-1,-1,GetShowTypeString (gShowType)); + ShellPrintEx(-1,-1,L"\n\n"); + +/* + // + // Get internal commands, such as change options. + // + Status = WaitEnter (); + if (EFI_ERROR (Status)) { + if (Status == EFI_ABORTED) { + return EFI_SUCCESS; + } + + return Status; + } +*/ + + // + // Searching and display structure info + // + Handle = QueryHandle; + for (Index = 0; Index < SMBiosTable->NumberOfSmbiosStructures; Index++) { + // + // if reach the end of table, break.. + // + if (Handle == INVALID_HANDLE) { + break; + } + // + // handle then point to the next! + // + if (LibGetSmbiosStructure (&Handle, &Buffer, &Length) != DMI_SUCCESS) { + break; + } + + SmbiosStruct.Raw = Buffer; + + // + // if QueryType==Random, print this structure. + // if QueryType!=Random, but Hdr->Type==QueryType, also print it. + // only if QueryType != Random and Hdr->Type != QueryType, skiped it. + // + if (QueryType != STRUCTURE_TYPE_RANDOM && SmbiosStruct.Hdr->Type != QueryType) { + continue; + } + + ShellPrintEx(-1,-1,L"\n=========================================================\n"); + ShellPrintHiiEx(-1,-1,NULL, + STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_TYPE_HANDLE_DUMP_STRUCT), + gShellDebug1HiiHandle, + SmbiosStruct.Hdr->Type, + SmbiosStruct.Hdr->Handle + ); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_INDEX_LENGTH), gShellDebug1HiiHandle, Index, Length); + // + // Addr of structure in structure in table + // + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_ADDR), gShellDebug1HiiHandle, (UINTN) Buffer); + DumpHex (0, 0, Length, Buffer); + +/* + // + // Get internal commands, such as change options. + // + Status = WaitEnter (); + if (EFI_ERROR (Status)) { + if (Status == EFI_ABORTED) { + return EFI_SUCCESS; + } + + return Status; + } +*/ + + if (gShowType != SHOW_NONE) { + // + // Print structure information + // + SmbiosPrintStructure (&SmbiosStruct, gShowType); + ShellPrintEx(-1,-1,L"\n"); + +/* + // + // Get internal commands, such as change options. + // + Status = WaitEnter (); + if (EFI_ERROR (Status)) { + if (Status == EFI_ABORTED) { + return EFI_SUCCESS; + } + + return Status; + } +*/ + } + if (!RandomView) { + break; + } + // + // Support Execution Interrupt. + // + if (ShellGetExecutionBreakFlag ()) { + return EFI_ABORTED; + } + } + + ShellPrintEx(-1,-1,L"\n=========================================================\n"); + return EFI_SUCCESS; + } + + return EFI_BAD_BUFFER_SIZE; +} + +/** + Query all structures Data from SMBIOS table and Display + the information to users as required display option. + + @param[in] QueryType Structure type to view. + @param[in] QueryHandle Structure handle to view. + @param[in] Option Display option: none,outline,normal,detail. + @param[in] RandomView Support for -h parameter. + + @retval EFI_SUCCESS print is successful. + @retval EFI_BAD_BUFFER_SIZE structure is out of the range of SMBIOS table. +**/ +EFI_STATUS +SMBios64View ( + IN UINT8 QueryType, + IN UINT16 QueryHandle, + IN UINT8 Option, + IN BOOLEAN RandomView + ) +{ + UINT16 Handle; + UINT8 *Buffer; + UINT16 Length; + UINTN Index; + SMBIOS_STRUCTURE_POINTER SmbiosStruct; + SMBIOS_TABLE_3_0_ENTRY_POINT *SMBiosTable; + + SMBiosTable = NULL; + LibSmbios64BitGetEPS (&SMBiosTable); + if (SMBiosTable == NULL) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_CANNOT_ACCESS_TABLE), gShellDebug1HiiHandle); + return EFI_BAD_BUFFER_SIZE; + } + + if (CompareMem (SMBiosTable->AnchorString, "_SM3_", 5) == 0) { + // + // Have got SMBIOS table + // + Smbios64BitPrintEPSInfo (SMBiosTable, Option); + + SmbiosMajorVersion = SMBiosTable->MajorVersion; + SmbiosMinorVersion = SMBiosTable->MinorVersion; + + ShellPrintEx(-1,-1,L"=========================================================\n"); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_QUERY_STRUCT_COND), gShellDebug1HiiHandle); + + if (QueryType == STRUCTURE_TYPE_RANDOM) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_QUERYTYPE_RANDOM), gShellDebug1HiiHandle); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_QUERYTYPE), gShellDebug1HiiHandle, QueryType); + } + + if (RandomView) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_QUERYHANDLE_RANDOM), gShellDebug1HiiHandle); + } else { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_QUERYHANDLE), gShellDebug1HiiHandle, QueryHandle); + } + + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_SHOWTYPE), gShellDebug1HiiHandle); + ShellPrintEx(-1,-1,GetShowTypeString (gShowType)); + ShellPrintEx(-1,-1,L"\n\n"); + +/* + // + // Get internal commands, such as change options. + // + Status = WaitEnter (); + if (EFI_ERROR (Status)) { + if (Status == EFI_ABORTED) { + return EFI_SUCCESS; + } + + return Status; + } +*/ + + // + // Searching and display structure info + // + Handle = QueryHandle; + for (Index = 0; Index < mNumberOfSmbios64BitStructures; Index++) { + // + // if reach the end of table, break.. + // + if (Handle == INVALID_HANDLE) { + break; + } + // + // handle then point to the next! + // + if (LibGetSmbios64BitStructure (&Handle, &Buffer, &Length) != DMI_SUCCESS) { + break; + } + + SmbiosStruct.Raw = Buffer; + + // + // if QueryType==Random, print this structure. + // if QueryType!=Random, but Hdr->Type==QueryType, also print it. + // only if QueryType != Random and Hdr->Type != QueryType, skiped it. + // + if (QueryType != STRUCTURE_TYPE_RANDOM && SmbiosStruct.Hdr->Type != QueryType) { + continue; + } + + ShellPrintEx(-1,-1,L"\n=========================================================\n"); + ShellPrintHiiEx(-1,-1,NULL, + STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_TYPE_HANDLE_DUMP_STRUCT), + gShellDebug1HiiHandle, + SmbiosStruct.Hdr->Type, + SmbiosStruct.Hdr->Handle + ); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_INDEX_LENGTH), gShellDebug1HiiHandle, Index, Length); + // + // Addr of structure in structure in table + // + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_ADDR), gShellDebug1HiiHandle, (UINTN) Buffer); + DumpHex (0, 0, Length, Buffer); + +/* + // + // Get internal commands, such as change options. + // + Status = WaitEnter (); + if (EFI_ERROR (Status)) { + if (Status == EFI_ABORTED) { + return EFI_SUCCESS; + } + + return Status; + } +*/ + + if (gShowType != SHOW_NONE) { + // + // Print structure information + // + SmbiosPrintStructure (&SmbiosStruct, gShowType); + ShellPrintEx(-1,-1,L"\n"); + +/* + // + // Get internal commands, such as change options. + // + Status = WaitEnter (); + if (EFI_ERROR (Status)) { + if (Status == EFI_ABORTED) { + return EFI_SUCCESS; + } + + return Status; + } +*/ + } + if (!RandomView) { + break; + } + // + // Support Execution Interrupt. + // + if (ShellGetExecutionBreakFlag ()) { + return EFI_ABORTED; + } + } + + ShellPrintEx(-1,-1,L"\n=========================================================\n"); + return EFI_SUCCESS; + } + + return EFI_BAD_BUFFER_SIZE; +} + +/** + Function to initialize the global mStatisticsTable object. + + @retval EFI_SUCCESS print is successful. +**/ +EFI_STATUS +InitSmbiosTableStatistics ( + VOID + ) +{ + UINT16 Handle; + UINT8 *Buffer; + UINT16 Length; + UINT16 Offset; + UINT16 Index; + + SMBIOS_STRUCTURE_POINTER SmbiosStruct; + SMBIOS_TABLE_ENTRY_POINT *SMBiosTable; + STRUCTURE_STATISTICS *StatisticsPointer; + + SMBiosTable = NULL; + LibSmbiosGetEPS (&SMBiosTable); + if (SMBiosTable == NULL) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_CANNOT_ACCESS_TABLE), gShellDebug1HiiHandle); + return EFI_NOT_FOUND; + } + + if (CompareMem (SMBiosTable->AnchorString, "_SM_", 4) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_SMBIOS_TABLE), gShellDebug1HiiHandle); + return EFI_INVALID_PARAMETER; + } + // + // Allocate memory to mStatisticsTable + // + if (mStatisticsTable != NULL) { + FreePool (mStatisticsTable); + mStatisticsTable = NULL; + } + + mStatisticsTable = (STRUCTURE_STATISTICS *) AllocateZeroPool (SMBiosTable->NumberOfSmbiosStructures * sizeof (STRUCTURE_STATISTICS)); + + if (mStatisticsTable == NULL) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_OUT_OF_MEM), gShellDebug1HiiHandle); + return EFI_OUT_OF_RESOURCES; + } + + Offset = 0; + StatisticsPointer = mStatisticsTable; + + // + // search from the first one + // + Handle = INVALID_HANDLE; + LibGetSmbiosStructure (&Handle, NULL, NULL); + for (Index = 1; Index <= SMBiosTable->NumberOfSmbiosStructures; Index++) { + // + // If reach the end of table, break.. + // + if (Handle == INVALID_HANDLE) { + break; + } + // + // After LibGetSmbiosStructure(), handle then point to the next! + // + if (LibGetSmbiosStructure (&Handle, &Buffer, &Length) != DMI_SUCCESS) { + break; + } + + SmbiosStruct.Raw = Buffer; + + // + // general statistics + // + StatisticsPointer->Index = Index; + StatisticsPointer->Type = SmbiosStruct.Hdr->Type; + StatisticsPointer->Handle = SmbiosStruct.Hdr->Handle; + StatisticsPointer->Length = Length; + StatisticsPointer->Addr = Offset; + + Offset = (UINT16) (Offset + Length); + + StatisticsPointer = &mStatisticsTable[Index]; + } + + return EFI_SUCCESS; +} + +/** + @param[in] Smbios64EntryPoint SMBIOS 64-bit entry point. + @param[out] NumberOfSmbios64Structures The number of structures in 64-bit SMBIOS table. + @param[out] Smbios64TableLength The total length of 64-bit SMBIOS table. + + @retval EFI_SUCCESS Calculation was successful. +**/ +EFI_STATUS +CalculateSmbios64BitStructureCountAndLength ( + SMBIOS_TABLE_3_0_ENTRY_POINT *Smbios64EntryPoint, + UINTN *NumberOfSmbios64Structures, + UINTN *Smbios64TableLength +) +{ + SMBIOS_STRUCTURE_POINTER Smbios; + UINT8 *Raw; + + *Smbios64TableLength = 0; + *NumberOfSmbios64Structures = 0; + + Smbios.Raw = (UINT8 *)(UINTN)(Smbios64EntryPoint->TableAddress); + while (TRUE) { + if (Smbios.Hdr->Type == 127) { + // + // Reach the end of table type 127 + // + (*NumberOfSmbios64Structures)++; + (*Smbios64TableLength) += sizeof (SMBIOS_STRUCTURE); + return EFI_SUCCESS; + } + + Raw = Smbios.Raw; + // + // Walk to next structure + // + LibGetSmbiosString (&Smbios, (UINT16) (-1)); + // + // Length = Next structure head - this structure head + // + (*Smbios64TableLength) += ((UINTN) Smbios.Raw - (UINTN) Raw); + if ((*Smbios64TableLength) > Smbios64EntryPoint->TableMaximumSize) { + // + // The actual table length exceeds maximum table size, + // There should be something wrong with SMBIOS table. + // + return EFI_INVALID_PARAMETER; + } + (*NumberOfSmbios64Structures)++; + } +} + +/** + Function to initialize the global mSmbios64BitStatisticsTable object. + + @retval EFI_SUCCESS print is successful. +**/ +EFI_STATUS +InitSmbios64BitTableStatistics ( + VOID + ) +{ + UINT16 Handle; + UINT8 *Buffer; + UINT16 Length; + UINT16 Offset; + UINT16 Index; + EFI_STATUS Status; + SMBIOS_STRUCTURE_POINTER SmbiosStruct; + SMBIOS_TABLE_3_0_ENTRY_POINT *SMBiosTable; + STRUCTURE_STATISTICS *StatisticsPointer; + + SMBiosTable = NULL; + LibSmbios64BitGetEPS (&SMBiosTable); + if (SMBiosTable == NULL) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_CANNOT_ACCESS_TABLE), gShellDebug1HiiHandle); + return EFI_NOT_FOUND; + } + + if (CompareMem (SMBiosTable->AnchorString, "_SM3_", 5) != 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_SMBIOS_TABLE), gShellDebug1HiiHandle); + return EFI_INVALID_PARAMETER; + } + // + // Allocate memory to mSmbios64BitStatisticsTable + // + if (mSmbios64BitStatisticsTable != NULL) { + FreePool (mSmbios64BitStatisticsTable); + mSmbios64BitStatisticsTable = NULL; + } + // + // Calculate number of smbios structures + // + Status = CalculateSmbios64BitStructureCountAndLength (SMBiosTable, &mNumberOfSmbios64BitStructures, &mSmbios64BitTableLength); + if ((EFI_ERROR (Status)) || (mSmbios64BitTableLength > SMBiosTable->TableMaximumSize)) { + return EFI_INVALID_PARAMETER; + } + + mSmbios64BitStatisticsTable = (STRUCTURE_STATISTICS *) AllocateZeroPool (mNumberOfSmbios64BitStructures * sizeof (STRUCTURE_STATISTICS)); + + if (mSmbios64BitStatisticsTable == NULL) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_OUT_OF_MEM), gShellDebug1HiiHandle); + return EFI_OUT_OF_RESOURCES; + } + + Offset = 0; + StatisticsPointer = mSmbios64BitStatisticsTable; + + // + // search from the first one + // + Handle = INVALID_HANDLE; + LibGetSmbios64BitStructure (&Handle, NULL, NULL); + for (Index = 1; Index <= mNumberOfSmbios64BitStructures; Index++) { + // + // If reach the end of table, break.. + // + if (Handle == INVALID_HANDLE) { + break; + } + // + // After LibGetSmbios64BitStructure(), handle then point to the next! + // + if (LibGetSmbios64BitStructure (&Handle, &Buffer, &Length) != DMI_SUCCESS) { + break; + } + + SmbiosStruct.Raw = Buffer; + + // + // general statistics + // + StatisticsPointer->Index = Index; + StatisticsPointer->Type = SmbiosStruct.Hdr->Type; + StatisticsPointer->Handle = SmbiosStruct.Hdr->Handle; + StatisticsPointer->Length = Length; + StatisticsPointer->Addr = Offset; + + Offset = (UINT16) (Offset + Length); + + StatisticsPointer = &mSmbios64BitStatisticsTable[Index]; + } + + return EFI_SUCCESS; +} + +/** + Function to display the global mStatisticsTable object. + + @param[in] Option ECHO, NORMAL, or DETAIL control the amount of detail displayed. + + @retval EFI_SUCCESS print is successful. +**/ +EFI_STATUS +DisplayStatisticsTable ( + IN UINT8 Option + ) +{ + UINTN Index; + UINTN Num; + STRUCTURE_STATISTICS *StatisticsPointer; + SMBIOS_TABLE_ENTRY_POINT *SMBiosTable; + + SMBiosTable = NULL; + if (Option < SHOW_OUTLINE) { + return EFI_SUCCESS; + } + // + // display EPS information firstly + // + LibSmbiosGetEPS (&SMBiosTable); + if (SMBiosTable == NULL) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_CANNOT_ACCESS_TABLE), gShellDebug1HiiHandle); + return EFI_UNSUPPORTED; + } + + ShellPrintEx(-1,-1,L"\n============================================================\n"); + SmbiosPrintEPSInfo (SMBiosTable, Option); + + if (Option < SHOW_NORMAL) { + return EFI_SUCCESS; + } + + if (mStatisticsTable == NULL) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_CANNOT_ACCESS_STATS), gShellDebug1HiiHandle); + return EFI_NOT_FOUND; + } + + ShellPrintEx(-1,-1,L"============================================================\n"); + StatisticsPointer = &mStatisticsTable[0]; + Num = SMBiosTable->NumberOfSmbiosStructures; + // + // display statistics table content + // + for (Index = 1; Index <= Num; Index++) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_INDEX), gShellDebug1HiiHandle, StatisticsPointer->Index); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_TYPE), gShellDebug1HiiHandle, StatisticsPointer->Type); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_HANDLE), gShellDebug1HiiHandle, StatisticsPointer->Handle); + if (Option >= SHOW_DETAIL) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_OFFSET), gShellDebug1HiiHandle, StatisticsPointer->Addr); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_LENGTH), gShellDebug1HiiHandle, StatisticsPointer->Length); + } + + ShellPrintEx(-1,-1,L"\n"); + StatisticsPointer = &mStatisticsTable[Index]; +/* + // + // Display 20 lines and wait for a page break + // + if (Index % 20 == 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_ENTER_CONTINUE), gShellDebug1HiiHandle); + Status = WaitEnter (); + if (EFI_ERROR (Status)) { + if (Status == EFI_ABORTED) { + return EFI_SUCCESS; + } + + return Status; + } + } +*/ + } + + return EFI_SUCCESS; +} + +/** + Function to display the global mSmbios64BitStatisticsTable object. + + @param[in] Option ECHO, NORMAL, or DETAIL control the amount of detail displayed. + + @retval EFI_SUCCESS print is successful. +**/ +EFI_STATUS +DisplaySmbios64BitStatisticsTable ( + IN UINT8 Option + ) +{ + UINTN Index; + UINTN Num; + STRUCTURE_STATISTICS *StatisticsPointer; + SMBIOS_TABLE_3_0_ENTRY_POINT *SMBiosTable; + + SMBiosTable = NULL; + if (Option < SHOW_OUTLINE) { + return EFI_SUCCESS; + } + // + // display EPS information firstly + // + LibSmbios64BitGetEPS (&SMBiosTable); + if (SMBiosTable == NULL) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_CANNOT_ACCESS_TABLE), gShellDebug1HiiHandle); + return EFI_UNSUPPORTED; + } + + ShellPrintEx(-1,-1,L"\n============================================================\n"); + Smbios64BitPrintEPSInfo (SMBiosTable, Option); + + if (Option < SHOW_NORMAL) { + return EFI_SUCCESS; + } + + if (mSmbios64BitStatisticsTable == NULL) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_CANNOT_ACCESS_STATS), gShellDebug1HiiHandle); + return EFI_NOT_FOUND; + } + + ShellPrintEx(-1,-1,L"============================================================\n"); + StatisticsPointer = &mSmbios64BitStatisticsTable[0]; + Num = mNumberOfSmbios64BitStructures; + // + // display statistics table content + // + for (Index = 1; Index <= Num; Index++) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_INDEX), gShellDebug1HiiHandle, StatisticsPointer->Index); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_TYPE), gShellDebug1HiiHandle, StatisticsPointer->Type); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_HANDLE), gShellDebug1HiiHandle, StatisticsPointer->Handle); + if (Option >= SHOW_DETAIL) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_OFFSET), gShellDebug1HiiHandle, StatisticsPointer->Addr); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_LENGTH), gShellDebug1HiiHandle, StatisticsPointer->Length); + } + + ShellPrintEx(-1,-1,L"\n"); + StatisticsPointer = &mSmbios64BitStatisticsTable[Index]; +/* + // + // Display 20 lines and wait for a page break + // + if (Index % 20 == 0) { + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_SMBIOSVIEW_SMBIOSVIEW_ENTER_CONTINUE), gShellDebug1HiiHandle); + Status = WaitEnter (); + if (EFI_ERROR (Status)) { + if (Status == EFI_ABORTED) { + return EFI_SUCCESS; + } + + return Status; + } + } +*/ + } + + return EFI_SUCCESS; +} + +/** + function to return a string of the detail level. + + @param[in] ShowType The detail level whose name is desired in clear text. + + @return A pointer to a string representing the ShowType (or 'undefined type' if not known). +**/ +CHAR16 * +GetShowTypeString ( + UINT8 ShowType + ) +{ + // + // show type + // + switch (ShowType) { + + case SHOW_NONE: + return L"SHOW_NONE"; + + case SHOW_OUTLINE: + return L"SHOW_OUTLINE"; + + case SHOW_NORMAL: + return L"SHOW_NORMAL"; + + case SHOW_DETAIL: + return L"SHOW_DETAIL"; + + case SHOW_ALL: + return L"SHOW_ALL"; + + default: + return L"Undefined type"; + } +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/SmbiosView.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/SmbiosView.h new file mode 100644 index 00000000..d129edd0 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/SmbiosView.h @@ -0,0 +1,123 @@ +/** @file + Tools of clarify the content of the smbios table. + + Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SMBIOS_VIEW_H_ +#define _SMBIOS_VIEW_H_ + +#define STRUCTURE_TYPE_RANDOM (UINT8) 0xFE +#define STRUCTURE_TYPE_INVALID (UINT8) 0xFF + +typedef struct { + UINT16 Index; + UINT8 Type; + UINT16 Handle; + UINT16 Addr; // offset from table head + UINT16 Length; // total structure length +} STRUCTURE_STATISTICS; + +/** + Query all structures Data from SMBIOS table and Display + the information to users as required display option. + + @param[in] QueryType Structure type to view. + @param[in] QueryHandle Structure handle to view. + @param[in] Option Display option: none,outline,normal,detail. + @param[in] RandomView Support for -h parameter. + + @retval EFI_SUCCESS print is successful. + @retval EFI_BAD_BUFFER_SIZE structure is out of the range of SMBIOS table. +**/ +EFI_STATUS +SMBiosView ( + IN UINT8 QueryType, + IN UINT16 QueryHandle, + IN UINT8 Option, + IN BOOLEAN RandomView + ); + +/** + Query all structures Data from SMBIOS table and Display + the information to users as required display option. + + @param[in] QueryType Structure type to view. + @param[in] QueryHandle Structure handle to view. + @param[in] Option Display option: none,outline,normal,detail. + @param[in] RandomView Support for -h parameter. + + @retval EFI_SUCCESS print is successful. + @retval EFI_BAD_BUFFER_SIZE structure is out of the range of SMBIOS table. +**/ +EFI_STATUS +SMBios64View ( + IN UINT8 QueryType, + IN UINT16 QueryHandle, + IN UINT8 Option, + IN BOOLEAN RandomView + ); + +/** + Function to initialize the global mStatisticsTable object. + + @retval EFI_SUCCESS print is successful. +**/ +EFI_STATUS +InitSmbiosTableStatistics ( + VOID + ); + +/** + Function to initialize the global mSmbios64BitStatisticsTable object. + + @retval EFI_SUCCESS print is successful. +**/ +EFI_STATUS +InitSmbios64BitTableStatistics ( + VOID + ); + +/** + Function to display the global mStatisticsTable object. + + @param[in] Option ECHO, NORMAL, or DETAIL control the amount of detail displayed. + + @retval EFI_SUCCESS print is successful. +**/ +EFI_STATUS +DisplayStatisticsTable ( + IN UINT8 Option + ); + +/** + Function to display the global mSmbios64BitStatisticsTable object. + + @param[in] Option ECHO, NORMAL, or DETAIL control the amount of detail displayed. + + @retval EFI_SUCCESS print is successful. +**/ +EFI_STATUS +DisplaySmbios64BitStatisticsTable ( + IN UINT8 Option + ); + +/** + function to return a string of the detail level. + + @param[in] ShowType The detail level whose name is desired in clear text. + + @return A pointer to a string representing the ShowType (or 'undefined type' if not known). +**/ +CHAR16* +GetShowTypeString ( + UINT8 ShowType + ); + +extern UINT8 gShowType; + +extern UINTN mSmbios64BitTableLength; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/SmbiosViewStrings.uni b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/SmbiosViewStrings.uni new file mode 100644 index 00000000..9433e8a2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/SmbiosViewStrings.uni @@ -0,0 +1,502 @@ +// /** +// +// Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+// (C) Copyright 2014-2015 Hewlett-Packard Development Company, L.P.
+// (C) Copyright 2015-2019 Hewlett Packard Enterprise Development LP
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// Module Name: +// +// UefiShellDebug1CommandsLib.uni +// +// Abstract: +// +// String definitions for UEFI Shell 2.0 Debug1 profile SmBiosView command +// +// +// **/ +/=# +#langdef en-US "english" +#string STR_SMBIOSVIEW_EVENTLOGINFO_ACCESS_METHOD #language en-US "Access method: " +#string STR_SMBIOSVIEW_EVENTLOGINFO_ONE_EIGHT_BIT #language en-US "Indexed I/O: 1 8-bit index port, 1 8-bit data port\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_TWO_EIGHT_BITS #language en-US "Indexed I/O: 2 8-bit index ports, 1 8-bit data port\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_ONE_SIXTEEN_BIT #language en-US "Indexed I/O: 1 16-bit index port, 1 8-bit data port\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_MEM_MAPPED_PHYS #language en-US "Memory-mapped physical 32-bit address\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_AVAIL_VIA_GENERAL #language en-US "Available via General-Purpose NonVolatile Data functions\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_AVAIL_FOR_FUTURE_ASSIGN #language en-US "Available for future assignment via this specification\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_BIOS_VENDOR_OEM #language en-US "BIOS Vendor/OEM-specific \r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_LOG_STATUS #language en-US "Log Status: " +#string STR_SMBIOSVIEW_EVENTLOGINFO_LOG_AREA_VALID #language en-US "Log area valid\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_LOG_AREA_FULL #language en-US "Log area full\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_LOG_AREA_NOT_FULL #language en-US "Log area not full\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_RES_BITS_NOT_ZERO #language en-US "Reserved bits not zero - 0x%x\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_LOG_HEADER_FORMAT #language en-US "Log Header Format: \r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_NO_HEADER #language en-US "No Header\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_TYPE_LOG_HEADER #language en-US "Type 1 log header\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_AVAIL_FOR_FUTURE #language en-US "Available for future\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_BIOS_VENDOR #language en-US "BIOS Vendor/OEM-specific format\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_LOG_HEADER_LEN #language en-US "Log Header Len: " +#string STR_SMBIOSVIEW_EVENTLOGINFO_ONE_VAR_D #language en-US " %d\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_THIS_RECORD_READ #language en-US "This record has been read\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_THIS_RECORD_NOT_READ #language en-US "This record has not been read\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_SYSTEM_EVENT_LOG #language en-US "System Event Log Header Type1 Format:\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_OEM_RESERVED #language en-US "OEM Reserved:\r\n0x%x 0x%x 0x%x 0x%x 0x%x\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_MULTIPLE_EVENT_TIME #language en-US "Multiple Event Time Window: 0x%x\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_MULTIPLE_EVENT_COUNT #language en-US "Multiple Event Count Increment: 0x%x\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_PREBOOT_ADDRESS #language en-US "Pre-boot Event Log Reset - CMOS Address: 0x%x\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_PREBOOT_INDEX #language en-US "Pre-boot Event Log Reset - CMOS Bit Index: 0x%x\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_CHECKSUM_STARTING_OFF #language en-US "CMOS Checksum - Starting Offset: 0x%x\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_CHECKSUN_BYTE_COUNT #language en-US "CMOS Checksum - Byte Count: 0x%x\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_RESERVED #language en-US "Reserved: 0x%x 0x%x 0x%x\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_HEADER_REVISION #language en-US "HeaderRevision: 0x%x\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_LOG_HEADER #language en-US "\r\nLog Header: " +#string STR_SMBIOSVIEW_EVENTLOGINFO_AVAIL_FUTURE_ASSIGN #language en-US "Available for future assignment via this specification\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_NO_STD_FORMAT #language en-US "No standard format data is available\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_SMBIOS_STRUCT_ASSOC #language en-US "SMBIOS structure associated with the hardware element that failed\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_STRUCT_HANDLE #language en-US "Structure handle = 0x%x\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_MULT_EVENT_COUNTER #language en-US "multiple-event counter: 0x%x\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_UNUSED_AVAIL_FOR_ASSIGN #language en-US "Unused, available for assignment by this specification\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_AVAIL_FOR_SYSTEM #language en-US "Available for system- and OEM-specific assignments\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_SYSTEM_EVENT_LOG_2 #language en-US "\r\nSystem Event Log records:\r\n" +#string STR_SMBIOSVIEW_EVENTLOGINFO_DATE #language en-US "Date/Time: " +#string STR_SMBIOSVIEW_EVENTLOGINFO_ERROR #language en-US "error" +#string STR_SMBIOSVIEW_EVENTLOGINFO_TIME_SIX_VARS #language en-US "%02x/%02x/%02x, %x:%x:%x\r\n" +#string STR_SMBIOSVIEW_LIBSMBIOSVIEW_CANNOT_GET_TABLE #language en-US "Cannot get SMBIOS Table\r\n" +#string STR_SMBIOSVIEW_LIBSMBIOSVIEW_GET_TABLE_ERROR #language en-US "Get SMBIOS Table error - %r\r\n" +#string STR_SMBIOSVIEW_LIBSMBIOSVIEW_NO_BUFF_LEN_SPEC #language en-US " Get SMBIOS Structure, no buffer or length specified!\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_DUMP #language en-US "Dump " +#string STR_SMBIOSVIEW_PRINTINFO_SIZE #language en-US "\r\nsize=%d:\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_SMBIOSTABLE_NULL #language en-US "SMBiosTable is NULL!\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_ENTRY_POINT_SIGN #language en-US "%HSMBIOS Entry Point Structure:%N\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_64_BIT_ENTRY_POINT_SIGN #language en-US "%HSMBIOS 3.0 (64-bit) Entry Point Structure:%N\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BCD_REVISION #language en-US "SMBIOS BCD Revision: 0x%x\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_DOCREV #language en-US "SMBIOS Docrev: 0x%x\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_NUMBER_STRUCT #language en-US "Number of Structures: %d\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_MAX_STRUCT_SIZE #language en-US "Max Struct size: %d\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_TABLE_ADDR #language en-US "Table Address: 0x%p\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_TABLE_LENGTH #language en-US "Table Length: %d\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_TABLE_MAX_SIZE #language en-US "Table Max Size: %d\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_ANCHOR_STR #language en-US "Anchor String: %a\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_EPS_CHECKSUM #language en-US "EPS Checksum: 0x%x\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_ENTRY_POINT_LEN #language en-US "Entry Point Len: %d\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_VERSION #language en-US "Version: %d.%d\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_MAJOR_VERSION #language en-US "Major version: %d\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_MINOR_VERSION #language en-US "Minor version: %d\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_ENTRY_POINT_REVISION #language en-US "Entry Point revision: 0x%x\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_FORMATTED_AREA_NONE #language en-US "Formatted Area: None\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_FORMATTED_AREA #language en-US "Formatted Area: \r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTER_ACHOR #language en-US "Inter Anchor: %a\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTER_CHECKSUM #language en-US "Inter Checksum: 0x%x\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_FORMAT_PART_LEN #language en-US "Format part Len : %d\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_STRUCT_HANDLE #language en-US "Structure Handle: %d\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BOOTUP_STATE #language en-US "Bootup state " +#string STR_SMBIOSVIEW_PRINTINFO_POWER_SUPPLY_STATE #language en-US "Power Supply State " +#string STR_SMBIOSVIEW_PRINTINFO_THERMAL_STATE #language en-US "Thermal state " +#string STR_SMBIOSVIEW_PRINTINFO_SECURITY_STATUS #language en-US "Security Status " +#string STR_SMBIOSVIEW_PRINTINFO_CONTAINED_ELEMENT #language en-US "Contained Element %d: " +#string STR_SMBIOSVIEW_PRINTINFO_SUPOPRT #language en-US "Support " +#string STR_SMBIOSVIEW_PRINTINFO_CURRENT #language en-US "Current " +#string STR_SMBIOSVIEW_PRINTINFO_INSTALLED #language en-US "Installed " +#string STR_SMBIOSVIEW_PRINTINFO_ENABLED #language en-US "Enabled " +#string STR_SMBIOSVIEW_PRINTINFO_EXTERNAL #language en-US "External " +#string STR_SMBIOSVIEW_PRINTINFO_SLOT_PEER_GROUPS #language en-US "Peer Groups %d:\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_SEGMENT_GROUP_NUM #language en-US " SegmentGroup Num: 0x%04x\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BUS_NUM #language en-US " Bus Num: 0x%02x\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_DEV_FUNC_NUM #language en-US " DevFunc Num: 0x%02x\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_DATA_BUS_WIDTH #language en-US " DataBus Width: %d\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_DESC_STRING #language en-US "Description String: " +#string STR_SMBIOSVIEW_PRINTINFO_SUPOPRTED_EVENT #language en-US "Supported Event Log Type Descriptors %d:\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_ACCESS_METHOD_NOT_SUPOPRTED #language en-US "Access Method %d has not supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_STRUCT_TYPE31 #language en-US "This structure is Type31, reserved by BIS (Boot Integrity Services)\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_MEM_DEVICE #language en-US "Memory Device %d:\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_DEV_LOAD #language en-US "Device Load: 0x%02x," +#string STR_SMBIOSVIEW_PRINTINFO_DEV_HANDLE #language en-US "Device Handle: 0x%04x\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INACTIVE_STRUCT #language en-US "Inactive structure --- Needn't interpret it.\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_THIS_STRUCT_END_TABLE #language en-US "This structure indicates the End-of-table!\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_STRUCT_TYPE_UNDEFINED #language en-US "Structure Type undefined!\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BIOS_CHAR #language en-US "BIOS Characteristics: \r\n" +#string STR_SMBIOSVIEW_PRINTINFO_RESERVED_BIT #language en-US "Reserved bit\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_UNKNOWN_BIT #language en-US "Unknown bit\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BIOS_CHAR_NOT_SUPPORTED #language en-US "BIOS Characteristics Not Supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_ISA_SUPPORTED #language en-US "ISA is supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_MSA_SUPPORTED #language en-US "MSA is supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_EISA_SUPPORTED #language en-US "EISA is supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_PCI_SUPPORTED #language en-US "PCI is supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_PC_CARD_SUPPORTED #language en-US "PC Card(PCMCIA) is supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_PLUG_PLAY_SUPPORTED #language en-US "Plug and play is supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_APM_SUPPORTED #language en-US "APM is supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BIOS_UPGRADEABLE #language en-US "BIOS is Upgradeable(FLASH)\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BIOS_SHADOWING #language en-US "BIOS shadowing is allowed\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_VESA_SUPPORTED #language en-US "VL-VESA is supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_ECSD_SUPPORT #language en-US "ESCD support is available\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BOOT_FROM_CD_SUPPORTED #language en-US "Boot from CD is supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_SELECTED_BOOT_SUPPORTED #language en-US "Selectable Boot is supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BIOS_ROM_SOCKETED #language en-US "BIOS ROM is socketed\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BOOT_FROM_PC_CARD #language en-US "Boot From PC Card(PCMCIA)is supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_EDD_ENHANCED_DRIVER #language en-US "EDD (Enhanced Disk Driver) Specification is supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_JAPANESE_FLOPPY_NEC #language en-US "Int 13h - Japanese Floppy for NEC 9800 1.2mb (3.5\",1k Bytes/Sector, 360 RPM) is supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_JAPANESE_FLOPPY_TOSHIBA #language en-US "Int 13h - Japanese Floppy for Toshiba 1.2mn (3.5\", 360 RPM) is supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_FLOPPY_SERVICES_SUPPORTED #language en-US "Int 13h - 5.25\"/360KB Floppy Services are supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_ONE_POINT_TWO_MB #language en-US "Int 13h - 5.25\"/1.2MB Floppy services are supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_720_KB #language en-US "Int 13h - 3.5\"/720KB Floppy services are supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_TWO_POINT_EIGHT_EIGHT_MB #language en-US "Int 13h - 3.5\"/2.88MB Floppy services are supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_PRINT_SCREEN_SUPPORT #language en-US "Int 5h, Print screen Services is supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_KEYBOARD_SERV_SUPPORT #language en-US "Int 9h, 8042 Keyboard services are supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_SERIAL_SERVICES_SUPPORT #language en-US "Int 14h, Serial Services are supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_PRINTER_SERVICES_SUPPORT #language en-US "Int 17h, Printer services are supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_MONO_VIDEO_SUPPORT #language en-US "Int 10h, CGA/Mono Video services are supported2\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_NEC_PC_98 #language en-US "NEC PC-98\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BITS_32_47 #language en-US " Bits 32:47 are reserved for BIOS Vendor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BITS_48_64 #language en-US " Bits 48:64 are reserved for System Vendor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BIOS_CHAR_EXTENSION #language en-US "BIOS Characteristics Extension Byte1:\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_ACPI_SUPPORTED #language en-US "ACPI supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_USB_LEGACY_SUPPORTED #language en-US "USB Legacy is supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_AGP_SUPPORTED #language en-US "AGP is supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_I2O_BOOT_SUPPORTED #language en-US "I2O boot is supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_LS_120_BOOT_SUPPORTED #language en-US "LS-120 boot is supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_ATAPI_ZIP_DRIVE #language en-US "ATAPI ZIP Drive boot is supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_1394_BOOT_SUPPORTED #language en-US "1394 boot is supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_SMART_BATTERY_SUPPORTED #language en-US "Smart battery supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BIOS_CHAR_EXTENSION_2 #language en-US "BIOS Characteristics Extension Byte2:\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BIOS_BOOT_SPEC_SUPP #language en-US "BIOS Boot Specification supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_FUNCTION_KEY_INIT #language en-US "Function key-initiated Network Service boot supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_ENABLE_TAR_CONT_DIST #language en-US "Enable Targeted Content Distribution\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_UEFI_SPEC_SUPPORT #language en-US "UEFI Specification is supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_VIRTUAL_MACHINE #language en-US "The SMBIOS table describes a virtual machine\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BITS_RSVD_FOR_FUTURE #language en-US " Bits %d:7 are reserved for future assignment\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_PROCESSOR_FAMILY #language en-US "Processor Family: " +#string STR_SMBIOSVIEW_PRINTINFO_OTHER #language en-US "Other\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_UNKNOWN #language en-US "Unknown\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL386_PROCESSOR #language en-US "Intel386(TM) Processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL486_PROCESSOR #language en-US "Intel486(TM) Processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_PENTIUM_PROC_FAMILY #language en-US "Pentium(R) Processor Family\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_PENTIUM_PRO_PROC #language en-US "Pentium(R) Pro processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_PENTIUM_II_PROC #language en-US "Pentium(R) II processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_PENTIUM_PROC_MMX #language en-US "Pentium(R) processor with MMX(TM) technology\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_CELERON_PROC #language en-US "Celeron(TM) processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_PENTIUM_XEON_PROC #language en-US "Pentium(R) II Xeon(TM) processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_PENTIUM_III_PROC #language en-US "Pentium(R) III Processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_M1_FAMILY #language en-US "M1 Family\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_K5_FAMILY #language en-US "K5 Family\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_POWER_PC_FAMILY #language en-US "Power PC Family\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_POWER_PC_601 #language en-US "Power PC 601\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_POWER_PC_603 #language en-US "Power PC 603\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_POWER_PC_603_PLUS #language en-US "Power PC 603+\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_POWER_PC_604 #language en-US "Power PC 604\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_ALPHA_FAMILY_2 #language en-US "Alpha Family 2\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_CORE_DUO #language en-US "Intel(R) Core(TM) Duo processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_CORE_DUO_MOBILE #language en-US "Intel(R) Core(TM) Duo mobile processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_CORE_SOLO_MOBILE #language en-US "Intel(R) Core(TM) Solo mobile processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_ATOM #language en-US "Intel(R) Atom(TM) processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_AMD_OPTERON_QUAD_CORE #language en-US "Quad-Core AMD Opteron(TM) Processor Family\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_AMD_OPTERON_THIRD_GENERATION #language en-US "Third-Generation AMD Opteron(TM) Processor Family\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_AMD_PHENOM_FX_QUAD_CORE #language en-US "AMD Phenom(TM) FX Quad-Core Processor Family\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_AMD_PHENOM_X4_QUAD_CORE #language en-US "AMD Phenom(TM) X4 Quad-Core Processor Family\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_AMD_PHENOM_X2_DUAL_CORE #language en-US "AMD Phenom(TM) X2 Dual-Core Processor Family\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_AMD_ATHLON_X2_DUAL_CORE #language en-US "AMD Athlon(TM) X2 Dual-Core Processor Family\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_3200_SERIES_QUAD_CORE #language en-US "Quad-Core Intel(R) Xeon(R) processor 3200 Series\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_3000_SERIES_DUAL_CORE #language en-US "Dual-Core Intel(R) Xeon(R) processor 3000 Series\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_5300_SERIES_QUAD_CORE #language en-US "Quad-Core Intel(R) Xeon(R) processor 5300 Series\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_5100_SERIES_DUAL_CORE #language en-US "Dual-Core Intel(R) Xeon(R) processor 5100 Series\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_5000_SERIES_DUAL_CORE #language en-US "Dual-Core Intel(R) Xeon(R) processor 5000 Series\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_LV_DUAL_CORE #language en-US "Dual-Core Intel(R) Xeon(R) processor LV\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_ULV_DUAL_CORE #language en-US "Dual-Core Intel(R) Xeon(R) processor ULV\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_7100_SERIES_DUAL_CORE #language en-US "Dual-Core Intel(R) Xeon(R) processor 7100 Series\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_5400_SERIES_QUAD_CORE #language en-US "Quad-Core Intel(R) Xeon(R) processor 5400 Series\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_QUAD_CORE #language en-US "Quad-Core Intel(R) Xeon(R) processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_5200_SERIES_DUAL_CORE #language en-US "Dual-Core Intel(R) Xeon(R) processor 5200 Series\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_7200_SERIES_DUAL_CORE #language en-US "Dual-Core Intel(R) Xeon(R) processor 7200 Series\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_7300_SERIES_QUAD_CORE #language en-US "Quad-Core Intel(R) Xeon(R) processor 7300 Series\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_7400_SERIES_QUAD_CORE #language en-US "Quad-Core Intel(R) Xeon(R) processor 7400 Series\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_7400_SERIES_MULTI_CORE #language en-US "Multi-Core Intel(R) Xeon(R) processor 7400 Series\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_CORE2_SOLO #language en-US "Intel(R) Core(TM)2 Solo processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_CORE2_EXTREME #language en-US "Intel(R) Core(TM)2 Extreme processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_CORE2_QUAD #language en-US "Intel(R) Core(TM)2 Quad processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_CORE2_EXTREME_MOBILE #language en-US "Intel(R) Core(TM)2 Extreme mobile processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_CORE2_DUO_MOBILE #language en-US "Intel(R) Core(TM)2 Duo mobile processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_CORE2_SOLO_MOBILE #language en-US "Intel(R) Core(TM)2 Solo mobile processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_CORE_I7 #language en-US "Intel(R) Core(TM) i7 processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_CELERON_DUAL_CORE #language en-US "Dual-Core Intel(R) Celeron(R) processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_MULTI_CORE #language en-US "Multi-Core Intel(R) Xeon(R) processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_3_SERIES_DUAL_CORE #language en-US "Dual-Core Intel(R) Xeon(R) processor 3xxx Series\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_3_SERIES_QUAD_CORE #language en-US "Quad-Core Intel(R) Xeon(R) processor 3xxx Series\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_5_SERIES_DUAL_CORE #language en-US "Dual-Core Intel(R) Xeon(R) processor 5xxx Series\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_5_SERIES_QUAD_CORE #language en-US "Quad-Core Intel(R) Xeon(R) processor 5xxx Series\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_7_SERIES_DUAL_CORE #language en-US "Dual-Core Intel(R) Xeon(R) processor 7xxx Series\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_7_SERIES_QUAD_CORE #language en-US "Quad-Core Intel(R) Xeon(R) processor 7xxx Series\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INTEL_XEON_7_SERIES_MULTI_CORE #language en-US "Multi-Core Intel(R) Xeon(R) processor 7xxx Series\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_AMD_OPTERON_3000_SERIES #language en-US "AMD Opteron(TM) 3000 Series Processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_AMD_SEMPRON_II #language en-US "AMD Sempron(TM) II Processor Family\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_AMD_FX_SERIES #language en-US "AMD FX(TM) Series Processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_AMD_Z_SERIES #language en-US "AMD Z-Series Processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_AMD_R_SERIES #language en-US "AMD R-Series Processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_AMD_OPTERON_4300_SERIES #language en-US "AMD Opteron(TM) 4300 Series Processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_AMD_OPTERON_6300_SERIES #language en-US "AMD Opteron(TM) 6300 Series Processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_AMD_OPTERON_3300_SERIES #language en-US "AMD Opteron(TM) 3300 Series Processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_AMD_OPTERON_FIREPRO_SERIES #language en-US "AMD FirePro(TM) Series Processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_AMD_EMBEDDED_OPTERON_QUAD_CORE #language en-US "Embedded AMD Opteron(TM) Quad-Core Processor Family\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_AMD_PHENOM_TRIPLE_CORE #language en-US "AMD Phenom(TM) Triple-Core Processor Family\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_AMD_TURION_ULTRA_DUAL_CORE_MOBILE #language en-US "AMD Turion(TM) Ultra Dual-Core Mobile Processor Family\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_AMD_TURION_DUAL_CORE_MOBILE #language en-US "AMD Turion(TM) Dual-Core Mobile Processor Family\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_AMD_ATHLON_DUAL_CORE #language en-US "AMD Athlon(TM) Dual-Core Processor Family\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_AMD_SEMPRON_SI #language en-US "AMD Sempron(TM) SI Processor Family\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_MIPS_FAMILY #language en-US "MIPS Family\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_SPARC_FAMILY #language en-US "SPARC Family\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_68040_FAMILY #language en-US "68040 Family\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_HOBBIT_FAMILY #language en-US "Hobbit Family\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_WEITEK #language en-US "Weitek\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_PA_RISC_FAMILY #language en-US "PA-RISC Family\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_V30_FAMILY #language en-US "V30 Family\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_PENTIUM_III_XEON #language en-US "Pentium(R) III Xeon(TM) Processor\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_RSVD_FOR_SPEC_M1 #language en-US "Reserved for specific M1 versions\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_RSVD_FOR_SPEC_K5 #language en-US "Reserved for specific K5 versions\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_RSVD_FOR_SPEC_PENTIUM #language en-US "Reserved for specific Pentium(R) Processor versions\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_UNDEFINED_PROC_FAMILY #language en-US "Undefined processor family and type\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_PROC_INFO #language en-US "Processor Information - Voltage:\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_PROC_CURRENT_VOLTAGE #language en-US "Processor current voltage = (%d/10)V\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_5V_SUPOPRTED #language en-US " 5V is supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_33V_SUPPORTED #language en-US " 3.3V is supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_29V_SUPPORTED #language en-US " 2.9V is supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BIT3_NOT_ZERO #language en-US "Error, reserved BIT 3 must be zero\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BIT4_NOT_ZERO #language en-US "Error, reserved BIT 4 must be zero\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BIT5_NOT_ZERO #language en-US "Error, reserved BIT 5 must be zero\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BIT6_NOT_ZERO #language en-US "Error, reserved BIT 6 must be zero\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BIT7_NOT_ZERO #language en-US "Error, reserved BIT 7 must be zero\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BIT10_NOT_ZERO #language en-US "Error, reserved BIT 10 must be zero\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BIT11_NOT_ZERO #language en-US "Error, reserved BIT 11 must be zero\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BIT12_NOT_ZERO #language en-US "Error, reserved BIT 12 must be zero\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BIT13_NOT_ZERO #language en-US "Error, reserved BIT 13 must be zero\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BIT14_NOT_ZERO #language en-US "Error, reserved BIT 14 must be zero\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BIT15_NOT_ZERO #language en-US "Error, reserved BIT 15 must be zero\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_PROC_STATUS #language en-US "Processor Status:\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_CPU_SOCKET_POPULATED #language en-US "CPU Socket Populated\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_CPU_SOCKET_UNPOPULATED #language en-US "CPU Socket Unpopulated\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_CPU_ENABLED #language en-US "CPU Enabled\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_CPU_DISABLED_BY_USER #language en-US "CPU Disabled by User via BIOS Setup\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_CPU_DIABLED_BY_BIOS #language en-US "CPU Disabled By BIOS (POST Error)\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_CPU_IDLE #language en-US "CPU is Idle, waiting to be enabled\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_OTHERS #language en-US "Others\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_RESERVED #language en-US "Reserved\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_SIZE_LARGEST_MEM #language en-US "The size of the largest memory module supported (per slot): " +#string STR_SMBIOSVIEW_PRINTINFO_ONE_VAR_MB #language en-US "%d * %d = %d MB\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_MAX_AMOUNT_MEM #language en-US "The maximum amount of memory supported by this controller: " +#string STR_SMBIOSVIEW_PRINTINFO_HANDLES_CONTROLLED #language en-US "There are %d Handles controlled by this controller\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_HANDLES_LIST_CONTROLLED #language en-US "Handles' List controlled by this controller:\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_HANDLE #language en-US "Handle%d: 0x%04x\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BANK_CONNECTIONS #language en-US "Bank Connections:" +#string STR_SMBIOSVIEW_PRINTINFO_BANK_RAS #language en-US "Banks %d & %d(RAS# %d & %d)\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BANK_RAS_2 #language en-US "Bank %d(RAS# %d)\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_NO_BANKS_CONNECTED #language en-US "No banks connected\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_MEMORY_SIZE #language en-US "Memory Size:" +#string STR_SMBIOSVIEW_PRINTINFO_MEM_SIZE_NOT_DETERMINABLE #language en-US " Memory Size Not determinable (Installed Size only)\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_MODULE_INSTALLED #language en-US " Module is installed, but no memory has been enabled\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_NOT_INSTALLED #language en-US " Not installed\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_MEM_SIZE #language en-US " Memory Size: %d MB\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_MEM_MODULE_DOUBLE_BANK #language en-US "The memory module has a Double-bank connection\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_MEM_MODULE_SINGLE_BANK #language en-US "The memory module has a Single-bank connection\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_SLOT_ID #language en-US " Slot Id:" +#string STR_SMBIOSVIEW_PRINTINFO_LOGICAL_MICRO_CHAN #language en-US " the logical Micro Channel slot number is:" +#string STR_SMBIOSVIEW_PRINTINFO_ONE_VAR_D #language en-US " %d\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_ERROR_NOT_1_15 #language en-US " error, not 1-15.\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_LOGICAL_EISA_NUM #language en-US " the logical EISA slot number is:" +#string STR_SMBIOSVIEW_PRINTINFO_IDENTIFIES_ADAPTER_NUM #language en-US " Identifies the Adapter Number is: %d\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_VALUE_PRESENT #language en-US " the value present in the Slot Number field of the PCI Interrupt Routing table entry that is associated with this slot is: %d\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_UNDEFINED_SLOT_ID #language en-US " undefined Slot Id\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_CACHE_CONFIGURATION #language en-US "Cache Configuration:\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_CACHE_WRITE_THROUGH #language en-US "Write Through\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_CACHE_WRITE_BACK #language en-US "Write Back\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_CACHE_VARIES_WITH_MEM_ADDR #language en-US "Varies with Memory Address\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_CACHE_INTERNAL #language en-US "Internal\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_CACHE_EXTERNAL #language en-US "External\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_CACHE_SOCKETED #language en-US "Socketed\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_CACHE_NOT_SOCKETED #language en-US "Not Socketed\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_CACHE_LEVEL #language en-US "Level %d\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_SYSTEM_BOOT_STATUS #language en-US "System Boot Status: " +#string STR_SMBIOSVIEW_PRINTINFO_NO_ERRORS_DETECTED #language en-US " No errors detected" +#string STR_SMBIOSVIEW_PRINTINFO_NO_BOOTABLE_MEDIA #language en-US " No bootable media" +#string STR_SMBIOSVIEW_PRINTINFO_NORMAL_OP_SYSTEM #language en-US " The \"normal\" unable to load operating system." +#string STR_SMBIOSVIEW_PRINTINFO_FIRMWARE_DETECTED #language en-US " Firmware-detected hardware problem, including \"unknown\" failure types." +#string STR_SMBIOSVIEW_PRINTINFO_OP_SYSTEM #language en-US " Operating system-detected hardware failure." +#string STR_SMBIOSVIEW_PRINTINFO_USER_REQUESTED_BOOT #language en-US " User-requested boot, usually via a keystroke" +#string STR_SMBIOSVIEW_PRINTINFO_SYSTEM_SECURITY_VIOLATION #language en-US " System security violation" +#string STR_SMBIOSVIEW_PRINTINFO_PREV_REQ_IMAGE #language en-US " Previously-requested image. " +#string STR_SMBIOSVIEW_PRINTINFO_WATCHDOG_TIMER #language en-US " A system watchdog timer expired, causing the system to reboot." +#string STR_SMBIOSVIEW_PRINTINFO_RSVD_FUTURE_ASSIGNMENT #language en-US " Reserved for future assignment via this specification. " +#string STR_SMBIOSVIEW_PRINTINFO_VENDOR_OEM_SPECIFIC #language en-US " Vendor/OEM-specific implementations. The Vendor/OEM identifier is the \"Manufacturer\" string found in the System Identification structure." +#string STR_SMBIOSVIEW_PRINTINFO_PRODUCT_SPEC_IMPLMENTATION #language en-US "Product-specific implementations. The product identifier is formed by the concatenation of the \"Manufacturer\" and \"Product Name\" strings found in the System Information structure." +#string STR_SMBIOSVIEW_PRINTINFO_ERROR_VALUE #language en-US "Error value\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_SBDS_MANUFACTURE_DATE #language en-US "SBDS Manufacture Date: " +#string STR_SMBIOSVIEW_PRINTINFO_MONTH_DAY_YEAR #language en-US "%02d/%02d/%4d\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_SYSTEM_RESET_CAPABILITIES #language en-US "System Reset Capabilities: " +#string STR_SMBIOSVIEW_PRINTINFO_BITS_RESERVED_ZERO #language en-US "Bits 7:6 are reserved bits, must be zero\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_WATCHDOG_TIMER_2 #language en-US "System contains a watchdog timer\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_SYSTEM_NOT_CONTAIN_TIMER #language en-US "System does not contain a watchdog timer\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BOOT_OPTION_LIMIT #language en-US "Boot Option on Limit: " +#string STR_SMBIOSVIEW_PRINTINFO_OP_SYSTEM_2 #language en-US "Operating system\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_SYSTEM_UTIL #language en-US "System utilities\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_DO_NOT_REBOOT #language en-US "Do not reboot\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BOOT_OPTION #language en-US "Boot Option :" +#string STR_SMBIOSVIEW_PRINTINFO_DO_NOT_REBOOT #language en-US "Do not reboot\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_HARDWARE_SECURITY_SET #language en-US "Hardware Security Settings: \r\n" +#string STR_SMBIOSVIEW_PRINTINFO_POWER_ON_PASSWORD #language en-US "Power-on Password Status: " +#string STR_SMBIOSVIEW_PRINTINFO_DISABLED #language en-US "Disabled\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_ENABLED_NEWLINE #language en-US "Enabled\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_NOT_IMPLEMENTED #language en-US "Not Implemented\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_KEYBOARD_PASSWORD #language en-US "Keyboard Password Status: " +#string STR_SMBIOSVIEW_PRINTINFO_ADMIN_PASSWORD_STATUS #language en-US "Administrator Password Status: " +#string STR_SMBIOSVIEW_PRINTINFO_FRONT_PANEL_RESET #language en-US "Front Panel Reset Status: " +#string STR_SMBIOSVIEW_PRINTINFO_CONNECTIONS #language en-US "Connections: " +#string STR_SMBIOSVIEW_PRINTINFO_BITS_RESERVED_ZERO_2 #language en-US "Bits 7:2 are reserved bits, must be zero\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_OUTBOUND_CONN_ENABLED #language en-US "Outbound Connection Enabled\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_OTUBOUND_CONN_DISABLED #language en-US "Outbound Connection Disabled\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INBOIUND_CONN_ENABLED #language en-US "Inbound Connection Enabled\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INBOUND_CONN_DISABLED #language en-US "Inbound Connection Disabled\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_POWER_SUPPLY_CHAR #language en-US "Power Supply Characteristics: \r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BITS_15_14_RSVD #language en-US "Bits 15:14 are reserved bits, must be zero\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_TYPE #language en-US "Type - " +#string STR_SMBIOSVIEW_PRINTINFO_OTHER_SPACE #language en-US " Other\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_LINEAR #language en-US " Linear\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_SWITCHING #language en-US " Switching\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BATTERY #language en-US " Battery\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_UPS #language en-US " UPS\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_CONVERTER #language en-US " Converter\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_REGULATOR #language en-US " Regulator\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_RESERVED_2 #language en-US " Reserved \r\n" +#string STR_SMBIOSVIEW_PRINTINFO_STATUS_DASH #language en-US " Status - " +#string STR_SMBIOSVIEW_PRINTINFO_OK #language en-US " OK\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_NON_CRITICAL #language en-US " Non-critical\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_CRITICAL_POWER_SUPPLY #language en-US " Critical, power supply has failed and has been taken off-line\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_UNDEFINED #language en-US " Undefined \r\n" +#string STR_SMBIOSVIEW_PRINTINFO_INPUT_VOLTAGE_RANGE #language en-US "Input Voltage Range Switching - " +#string STR_SMBIOSVIEW_PRINTINFO_MANUAL #language en-US " Manual\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_AUTO_SWITCH #language en-US " Auto-switch\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_WIDE_RANGE #language en-US " Wide range\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_NOT_APPLICABLE #language en-US " Not applicable\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_RESERVED_3 #language en-US " Reserved \r\n" +#string STR_SMBIOSVIEW_PRINTINFO_POWER_SUPPLY_UNPLUGGED #language en-US "Power supply is unplugged from the wall\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_POWER_SUPPLY_PLUGGED #language en-US "Power supply is plugged into the wall\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_POWER_SUPPLY_PRESENT #language en-US "Power supply is present\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_POWER_SUPPLY_NOT_PRESENT #language en-US "Power supply is not present\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_POWER_SUPPLY_REPLACE #language en-US "Power supply is hot replaceable\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_POWER_SUPPLY_NOT_REPLACE #language en-US "Power supply is not hot replaceable\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BIOS_SIZE #language en-US "BiosSize: %d KB\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_EXTENDED_BIOS_SIZE #language en-US "ExtendedBiosSize: %d %s\r\n" +#string STR_SMBIOSVIEW_QUERYTABLE_NO_INFO #language en-US "No Info" +#string STR_SMBIOSVIEW_QUERYTABLE_RSVD_BITS_SET #language en-US "\r\nIt also has reserved bits set 1 --- reserved bits: 0x%x" +#string STR_SMBIOSVIEW_QUERYTABLE_SYSTEM_WAKEUP_TYPE #language en-US "System Wakeup Type:" +#string STR_SMBIOSVIEW_QUERYTABLE_BASE_BOARD_FEATURE_FLAGS #language en-US "Base Board Feature Flags:" +#string STR_SMBIOSVIEW_QUERYTABLE_BASE_BOARD_BOARD_TYPE #language en-US "Base Board Board Type:" +#string STR_SMBIOSVIEW_QUERYTABLE_SYSTEM_CHASSIS_TYPE #language en-US "System Enclosure or Chassis Types:" +#string STR_SMBIOSVIEW_QUERYTABLE_CHASSIS_LOCK_PRESENT #language en-US "Chassis Lock present\r\n" +#string STR_SMBIOSVIEW_QUERYTABLE_SYSTEM_CHASSIS_STATUS #language en-US "System Enclosure or Chassis Status: " +#string STR_SMBIOSVIEW_QUERYTABLE_SYSTEM_CHASSIS_SECURITY #language en-US "System Enclosure or Chassis Security Status: " +#string STR_SMBIOSVIEW_QUERYTABLE_PROC_TYPE #language en-US "Processor Type: " +#string STR_SMBIOSVIEW_QUERYTABLE_PROC_UPDATE #language en-US "Processor Upgrade: " +#string STR_SMBIOSVIEW_QUERYTABLE_PROC_CHARACTERISTICS #language en-US "Processor Characteristics: " +#string STR_SMBIOSVIEW_QUERYTABLE_MEM_DETECTMETHOD #language en-US "Memory Controller Error DetectMethod:" +#string STR_SMBIOSVIEW_QUERYTABLE_MEM_CORRECT_CAPABILITY #language en-US "Memory Controller Error Correct Capability:\r\n" +#string STR_SMBIOSVIEW_QUERYTABLE_MEM_INTERLEAVE_SUPPORT #language en-US "Memory Controller Interleave Support:" +#string STR_SMBIOSVIEW_QUERYTABLE_MEM_MEMORY_SPEED #language en-US "Memory Controller Memory Speed:" +#string STR_SMBIOSVIEW_QUERYTABLE_REQUIRED_VOLTAGES #language en-US "The required voltages for each memory module sockets:\r\n" +#string STR_SMBIOSVIEW_QUERYTABLE_MEM_MODULE_TYPE #language en-US "Memory Module Memory Type: " +#string STR_SMBIOSVIEW_QUERYTABLE_MEM_MODULE_ERROR_STATUS #language en-US "Memory Module Error Status: " +#string STR_SMBIOSVIEW_QUERYTABLE_CACHE_SRAM_TYPE #language en-US "Cache SRAM Type: " +#string STR_SMBIOSVIEW_QUERYTABLE_CACHE_ERROR_CORRECTING #language en-US "Cache Error Correcting Type: " +#string STR_SMBIOSVIEW_QUERYTABLE_CACHE_SYSTEM_TYPE #language en-US "Cache System Cache Type:" +#string STR_SMBIOSVIEW_QUERYTABLE_CACHE_ASSOCIATIVITY #language en-US "Cache Associativity:" +#string STR_SMBIOSVIEW_QUERYTABLE_PORT_CONNECTOR_TYPE #language en-US "Port Connector Type: " +#string STR_SMBIOSVIEW_QUERYTABLE_PORT_TYPE #language en-US "Port Type: " +#string STR_SMBIOSVIEW_QUERYTABLE_SYSTEM_SLOT_TYPE #language en-US "System Slot Type: " +#string STR_SMBIOSVIEW_QUERYTABLE_SYSTEM_SLOT_DATA #language en-US "System Slot Data Bus Width: " +#string STR_SMBIOSVIEW_QUERYTABLE_SYSTEM_SLOT_CURRENT_USAGE #language en-US "System Slot Current Usage: " +#string STR_SMBIOSVIEW_QUERYTABLE_SYSTEM_SLOT_LENGTH #language en-US "System Slot Length: " +#string STR_SMBIOSVIEW_QUERYTABLE_SLOT_CHARACTERISTICS #language en-US "Slot characteristics 1: " +#string STR_SMBIOSVIEW_QUERYTABLE_SLOT_CHARACTERISTICS_2 #language en-US "Slot characteristics 2: " +#string STR_SMBIOSVIEW_QUERYTABLE_ONBOARD_DEVICE_TYPE #language en-US "Onboard Device Type: " +#string STR_SMBIOSVIEW_QUERYTABLE_SYSTEM_EVENT_LOG_TYPE #language en-US "System Event Log Type: " +#string STR_SMBIOSVIEW_QUERYTABLE_EVENT_LOG_VAR_DATA_FORMAT #language en-US "Event Log Variable Data Format Types: " +#string STR_SMBIOSVIEW_QUERYTABLE_POST_RESULTS_BITMAP #language en-US "POST Results Bitmap - First DWORD:\r\n" +#string STR_SMBIOSVIEW_QUERYTABLE_POST_RESULTS_SECOND_DWORD #language en-US "POST Results Bitmap - Second DWORD:\r\n" +#string STR_SMBIOSVIEW_QUERYTABLE_SYSTEM_MANAGEMENT_TYPES #language en-US "System Management Types: " +#string STR_SMBIOSVIEW_QUERYTABLE_OEM_ASSIGNED #language en-US "OEM assigned\r\n" +#string STR_SMBIOSVIEW_QUERYTABLE_RSVD_FOR_FUTURE_ASSIGN #language en-US "Reserved for future assignment via this specification\r\n" +#string STR_SMBIOSVIEW_QUERYTABLE_SYSTEM_MANAGEMENT_PROBE #language en-US "A system-management probe or cooling device is out-of-range\r\n" +#string STR_SMBIOSVIEW_QUERYTABLE_PHYS_MEM_ARRAY_LOCATION #language en-US "Physical Memory Array Location: " +#string STR_SMBIOSVIEW_QUERYTABLE_PHYS_MEM_ARRAY_USE #language en-US "Physical Memory Array Use: " +#string STR_SMBIOSVIEW_QUERYTABLE_PHYS_MEM_ARRAY_ERROR #language en-US "Physical Memory Array Error Correction Types: " +#string STR_SMBIOSVIEW_QUERYTABLE_MEM_DEVICE_FORM_FACTOR #language en-US "Memory Device - Form Factor: " +#string STR_SMBIOSVIEW_QUERYTABLE_MEM_DEVICE_TYPE #language en-US "Memory Device - Type: " +#string STR_SMBIOSVIEW_QUERYTABLE_MEM_DEVICE_TYPE_DETAIL #language en-US "Memory Device - Type Detail: " +#string STR_SMBIOSVIEW_QUERYTABLE_MEM_DEVICE_MEMORY_TECHNOLOGY #language en-US "Memory Device - Memory Technology: " +#string STR_SMBIOSVIEW_QUERYTABLE_MEM_DEVICE_MEM_OPER_MODE_CAPA #language en-US "Memory Device - Memory Operating Mode Capability: " +#string STR_SMBIOSVIEW_QUERYTABLE_MEM_ERROR_INFO #language en-US "32-bit Memory Error Information - Type: " +#string STR_SMBIOSVIEW_QUERYTABLE_MEM_ERROR_GRANULARITY #language en-US "Memory Error - Error granularity: " +#string STR_SMBIOSVIEW_QUERYTABLE_MEM_ERROR_OP #language en-US "Memory Error - Error Operation: " +#string STR_SMBIOSVIEW_QUERYTABLE_POINTING_DEVICE_TYPE #language en-US "Pointing Device - Type: " +#string STR_SMBIOSVIEW_QUERYTABLE_POINTING_DEVICE_INTERFACE #language en-US "Pointing Device - Interface:" +#string STR_SMBIOSVIEW_QUERYTABLE_PORTABLE_BATT_DEV_CHEM #language en-US "Portable Battery - Device Chemistry:" +#string STR_SMBIOSVIEW_QUERYTABLE_VOLTAGE_PROBE_LOC #language en-US "Voltage Probe - Location:" +#string STR_SMBIOSVIEW_QUERYTABLE_VOLTAGE_PROBE_STATUS #language en-US "Voltage Probe - Status:" +#string STR_SMBIOSVIEW_QUERYTABLE_COOLING_DEV_STATUS #language en-US "Cooling Device - Status: " +#string STR_SMBIOSVIEW_QUERYTABLE_COOLING_DEV_TYPE #language en-US "Cooling Device - Type: " +#string STR_SMBIOSVIEW_QUERYTABLE_TEMP_PROBE #language en-US "Temperature Probe - Status:" +#string STR_SMBIOSVIEW_QUERYTABLE_ELEC_PROBE_STATUS #language en-US "Electrical Current Probe - Status:" +#string STR_SMBIOSVIEW_QUERYTABLE_ELEC_PROBE_LOC #language en-US "Electrical Current Probe - Location:" +#string STR_SMBIOSVIEW_QUERYTABLE_MANAGEMENT_DEV_TYPE #language en-US "Management Device Type:" +#string STR_SMBIOSVIEW_QUERYTABLE_MANAGEMENT_DEV_ADDR_TYPE #language en-US "Management Device - Address Type:" +#string STR_SMBIOSVIEW_QUERYTABLE_MEM_CHANNEL_TYPE #language en-US "Memory Channel Type:" +#string STR_SMBIOSVIEW_QUERYTABLE_BMC_INTERFACE_TYPE #language en-US "BMC Interface Type:" +#string STR_SMBIOSVIEW_QUERYTABLE_MC_HOST_INTERFACE_TYPE #language en-US "MC Host Interface Type:" +#string STR_SMBIOSVIEW_QUERYTABLE_STRUCT_TYPE #language en-US "Structure Type:" +#string STR_SMBIOSVIEW_QUERYTABLE_PROCESSOR_ARCH_TYPE #language en-US "Processor Architecture Type:" +#string STR_SMBIOSVIEW_SMBIOSVIEW_ONE_VAR_ARGV #language en-US "%s " +#string STR_SMBIOSVIEW_SMBIOSVIEW_QUERY_STRUCT_COND #language en-US "Query Structure, conditions are:\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_QUERYTYPE_RANDOM #language en-US "QueryType = Random \r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_QUERYTYPE #language en-US "QueryType = %d\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_QUERYHANDLE_RANDOM #language en-US "QueryHandle = Random\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_QUERYHANDLE #language en-US "QueryHandle = 0x%x\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_SHOWTYPE #language en-US "ShowType = " +#string STR_SMBIOSVIEW_SMBIOSVIEW_TYPE_HANDLE_DUMP_STRUCT #language en-US "Type=%d, Handle=0x%x\r\nDump Structure as:\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_INDEX_LENGTH #language en-US "Index=%d,Length=0x%x," +#string STR_SMBIOSVIEW_SMBIOSVIEW_ADDR #language en-US "Addr=0x%p\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_ENTRYLEN #language en-US "Entry Length: 0x%x\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_REFERENCEDHANDLE #language en-US "Referenced Handle: 0x%x\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_REFERENCEDOFFSET #language en-US "Referenced Offset: 0x%x\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_ENTER_Q #language en-US "\r\n%HEnter%N to continue, %H:q%N to exit, %H:[0-3]%N to change mode, %H/?%N for help\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_SMBIOS_UTILITY #language en-US " SMBIOS Utility ---- smbiosview HELP Information\r\n\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_USAGE #language en-US "Usage:\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_HSMBIOSVIEW #language en-US "%Hsmbiosview [-t type] | [-h handle] | [-s] | [-a]%N\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_EXAMPLES #language en-US "Examples:\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_SHOW_STAT_INFO #language en-US "%H>smbiosview -s %N - Show statistics information\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_SHOW_ALL_STRUCT_TYPE #language en-US "%H>smbiosview -t 8 %N - Show all structures of type=8\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_SHOW_STRUCT_HANDLE #language en-US "%H>smbiosview -h 25 %N - Show structure of handle=0x25\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_SHOW_ALL_OUTPUT_TO_FILE #language en-US "%H>smbiosview -a > 1.log%N - Show all and output to file 1.log\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_INTERNAL_COMMANDS #language en-US "Internal commands:\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_QUIT_SMBIOSVIEW #language en-US "%H:q%N -------- quit smbiosview\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_CHANGE_DISPLAY_NONE #language en-US "%H:0%N -------- Change smbiosview display NONE info\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_CHANGE_DISPLAY_OUTLINE #language en-US "%H:1%N -------- Change smbiosview display OUTLINE info\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_CHANGE_DISPLAY_NORMAL #language en-US "%H:2%N -------- Change smbiosview display NORMAL info\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_CHANGE_DISPLAY_DETAIL #language en-US "%H:3%N -------- Change smbiosview display DETAIL info\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_SHOW_HELP #language en-US "%H/?%N -------- Show help\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_INDEX #language en-US "Index=%04d " +#string STR_SMBIOSVIEW_SMBIOSVIEW_TYPE #language en-US "Type=%03d " +#string STR_SMBIOSVIEW_SMBIOSVIEW_HANDLE #language en-US "Handle=0x%04x " +#string STR_SMBIOSVIEW_SMBIOSVIEW_OFFSET #language en-US "Offset=0x%04x " +#string STR_SMBIOSVIEW_SMBIOSVIEW_LENGTH #language en-US "Length=0x%04x" +#string STR_SMBIOSVIEW_SMBIOSVIEW_ENTER_CONTINUE #language en-US "Press Enter to continue..\r\n" +#string STR_SMBIOSVIEW_LIBSMBIOSVIEW_NO_BUF_SPEC_WHEN_STRUCT #language en-US "smbiosview: No buffer specified when get structure\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_NOT_SPEC #language en-US "SmbiosView: Type # not specified\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_HANDLE_NOT_SPEC #language en-US "SmbiosView: Handle # not specified\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_UNKNOWN_FLAG #language en-US "\r\nSmbiosView: Unknown flag\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_CANNOT_ACCESS_TABLE #language en-US "SmbiosView: Cannot access SMBIOS table\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_UNKNOWN_INTERNAL_COMMAND #language en-US "\r\nSmbiosView: Unknown internal command\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_SMBIOS_TABLE #language en-US "SmbiosView: SMBIOS table damaged\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_OUT_OF_MEM #language en-US "SmbiosView: Out of memory\r\n" +#string STR_SMBIOSVIEW_SMBIOSVIEW_CANNOT_ACCESS_STATS #language en-US "SmbiosView: Cannot access statistics table\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_TPM_DEVICE_CHAR #language en-US "TPM Device Characteristics: \r\n" +#string STR_SMBIOSVIEW_PRINTINFO_TPM_DEVICE_CHAR_NOT_SUPPORTED #language en-US "TPM Device Characteristics Not Supported\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_TPM_DEVICE_CONFIG_FWU #language en-US "Family configurable via firmware update\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_TPM_DEVICE_CONFIG_PLAT_SW #language en-US "Family configurable via platform software support\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_TPM_DEVICE_CONFIG_OEM #language en-US "Family configurable via OEM proprietary mechanism\r\n" +#string STR_SMBIOSVIEW_PRINTINFO_BITS_06_63 #language en-US "Bits 6:63 are reserved\r\n" + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.c new file mode 100644 index 00000000..6530bc7c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.c @@ -0,0 +1,421 @@ +/** @file + Main file for NULL named library for debug1 profile shell command functions. + + Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDebug1CommandsLib.h" +#include + +STATIC CONST CHAR16 mFileName[] = L"Debug1Commands"; +EFI_HII_HANDLE gShellDebug1HiiHandle = NULL; + +/** + Gets the debug file name. This will be used if HII is not working. + + @retval NULL No file is available. + @return The NULL-terminated filename to get help from. +**/ +CONST CHAR16* +EFIAPI +ShellCommandGetManFileNameDebug1 ( + VOID + ) +{ + return (mFileName); +} + +/** + Constructor for the Shell Debug1 Commands library. + + @param ImageHandle the image handle of the process + @param SystemTable the EFI System Table pointer + + @retval EFI_SUCCESS the shell command handlers were installed sucessfully + @retval EFI_UNSUPPORTED the shell level required was not found. +**/ +EFI_STATUS +EFIAPI +UefiShellDebug1CommandsLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + // + // check our bit of the profiles mask + // + if ((PcdGet8(PcdShellProfileMask) & BIT1) == 0) { + return (EFI_SUCCESS); + } + + // + // install the HII stuff. + // + gShellDebug1HiiHandle = HiiAddPackages (&gShellDebug1HiiGuid, gImageHandle, UefiShellDebug1CommandsLibStrings, NULL); + if (gShellDebug1HiiHandle == NULL) { + return (EFI_DEVICE_ERROR); + } + + // + // install our shell command handlers that are always installed + // + ShellCommandRegisterCommandName(L"setsize", ShellCommandRunSetSize , ShellCommandGetManFileNameDebug1, 0, L"Debug1", TRUE, gShellDebug1HiiHandle, STRING_TOKEN(STR_GET_HELP_SETSIZE) ); + ShellCommandRegisterCommandName(L"comp", ShellCommandRunComp , ShellCommandGetManFileNameDebug1, 0, L"Debug1", TRUE, gShellDebug1HiiHandle, STRING_TOKEN(STR_GET_HELP_COMP) ); + ShellCommandRegisterCommandName(L"mode", ShellCommandRunMode , ShellCommandGetManFileNameDebug1, 0, L"Debug1", TRUE, gShellDebug1HiiHandle, STRING_TOKEN(STR_GET_HELP_MODE) ); + ShellCommandRegisterCommandName(L"memmap", ShellCommandRunMemMap , ShellCommandGetManFileNameDebug1, 0, L"Debug1", TRUE, gShellDebug1HiiHandle, STRING_TOKEN(STR_GET_HELP_MEMMAP) ); + ShellCommandRegisterCommandName(L"eficompress", ShellCommandRunEfiCompress , ShellCommandGetManFileNameDebug1, 0, L"Debug1", TRUE, gShellDebug1HiiHandle, STRING_TOKEN(STR_GET_HELP_EFICOMPRESS) ); + ShellCommandRegisterCommandName(L"efidecompress", ShellCommandRunEfiDecompress , ShellCommandGetManFileNameDebug1, 0, L"Debug1", TRUE, gShellDebug1HiiHandle, STRING_TOKEN(STR_GET_HELP_EFIDCOMPRESS) ); + ShellCommandRegisterCommandName(L"dmem", ShellCommandRunDmem , ShellCommandGetManFileNameDebug1, 0, L"Debug1", TRUE, gShellDebug1HiiHandle, STRING_TOKEN(STR_GET_HELP_DMEM) ); + ShellCommandRegisterCommandName(L"loadpcirom", ShellCommandRunLoadPciRom , ShellCommandGetManFileNameDebug1, 0, L"Debug1", TRUE, gShellDebug1HiiHandle, STRING_TOKEN(STR_GET_HELP_LOAD_PCI_ROM) ); + ShellCommandRegisterCommandName(L"mm", ShellCommandRunMm , ShellCommandGetManFileNameDebug1, 0, L"Debug1", TRUE, gShellDebug1HiiHandle, STRING_TOKEN(STR_GET_HELP_MM) ); + ShellCommandRegisterCommandName(L"setvar", ShellCommandRunSetVar , ShellCommandGetManFileNameDebug1, 0, L"Debug1", TRUE, gShellDebug1HiiHandle, STRING_TOKEN(STR_GET_HELP_SETVAR) ); + ShellCommandRegisterCommandName(L"sermode", ShellCommandRunSerMode , ShellCommandGetManFileNameDebug1, 0, L"Debug1", TRUE, gShellDebug1HiiHandle, STRING_TOKEN(STR_GET_HELP_SERMODE) ); + ShellCommandRegisterCommandName(L"pci", ShellCommandRunPci , ShellCommandGetManFileNameDebug1, 0, L"Debug1", TRUE, gShellDebug1HiiHandle, STRING_TOKEN(STR_GET_HELP_PCI) ); + ShellCommandRegisterCommandName(L"smbiosview", ShellCommandRunSmbiosView , ShellCommandGetManFileNameDebug1, 0, L"Debug1", TRUE, gShellDebug1HiiHandle, STRING_TOKEN(STR_GET_HELP_SMBIOSVIEW) ); + ShellCommandRegisterCommandName(L"dmpstore", ShellCommandRunDmpStore , ShellCommandGetManFileNameDebug1, 0, L"Debug1", TRUE, gShellDebug1HiiHandle, STRING_TOKEN(STR_GET_HELP_DMPSTORE) ); + ShellCommandRegisterCommandName(L"dblk", ShellCommandRunDblk , ShellCommandGetManFileNameDebug1, 0, L"Debug1", TRUE, gShellDebug1HiiHandle, STRING_TOKEN(STR_GET_HELP_DBLK) ); + ShellCommandRegisterCommandName(L"edit", ShellCommandRunEdit , ShellCommandGetManFileNameDebug1, 0, L"Debug1", TRUE, gShellDebug1HiiHandle, STRING_TOKEN(STR_GET_HELP_EDIT) ); + ShellCommandRegisterCommandName(L"hexedit", ShellCommandRunHexEdit , ShellCommandGetManFileNameDebug1, 0, L"Debug1", TRUE, gShellDebug1HiiHandle, STRING_TOKEN(STR_GET_HELP_HEXEDIT) ); + + ShellCommandRegisterAlias(L"dmem", L"mem"); + + BcfgLibraryRegisterBcfgCommand(ImageHandle, SystemTable, L"Debug1"); + + return (EFI_SUCCESS); +} + +/** + Destructor for the library. free any resources. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. +**/ +EFI_STATUS +EFIAPI +UefiShellDebug1CommandsLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + if (gShellDebug1HiiHandle != NULL) { + HiiRemovePackages(gShellDebug1HiiHandle); + } + + BcfgLibraryUnregisterBcfgCommand(ImageHandle, SystemTable); + return (EFI_SUCCESS); +} + + +/** + Function returns a system configuration table that is stored in the + EFI System Table based on the provided GUID. + + @param[in] TableGuid A pointer to the table's GUID type. + @param[in, out] Table On exit, a pointer to a system configuration table. + + @retval EFI_SUCCESS A configuration table matching TableGuid was found. + @retval EFI_NOT_FOUND A configuration table matching TableGuid was not found. +**/ +EFI_STATUS +GetSystemConfigurationTable ( + IN EFI_GUID *TableGuid, + IN OUT VOID **Table + ) +{ + UINTN Index; + ASSERT (Table != NULL); + + for (Index = 0; Index < gST->NumberOfTableEntries; Index++) { + if (CompareGuid (TableGuid, &(gST->ConfigurationTable[Index].VendorGuid))) { + *Table = gST->ConfigurationTable[Index].VendorTable; + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** + Clear the line at the specified Row. + + @param[in] Row The row number to be cleared ( start from 1 ) + @param[in] LastCol The last printable column. + @param[in] LastRow The last printable row. +**/ +VOID +EditorClearLine ( + IN UINTN Row, + IN UINTN LastCol, + IN UINTN LastRow + ) +{ + UINTN Col; + CHAR16 Line[200]; + + if (Row == 0) { + Row = 1; + } + + // + // prepare a blank line + // If max column is larger, split to multiple prints. + // + SetMem16 (Line, sizeof (Line), L' '); + Line[ARRAY_SIZE (Line) - 1] = CHAR_NULL; + + for (Col = 1; Col <= LastCol; Col += ARRAY_SIZE (Line) - 1) { + if (Col + ARRAY_SIZE (Line) - 1 > LastCol) { + if (Row == LastRow) { + // + // if CHAR_NULL is still at position LastCol, it will cause first line error + // + Line[(LastCol - 1) % (ARRAY_SIZE (Line) - 1)] = CHAR_NULL; + } else { + Line[LastCol % (ARRAY_SIZE (Line) - 1)] = CHAR_NULL; + } + } + + // + // print out the blank line + // + ShellPrintEx ((INT32) Col - 1, (INT32) Row - 1, Line); + } +} + +/** + Determine if the character is valid for a filename. + + @param[in] Ch The character to test. + + @retval TRUE The character is valid. + @retval FALSE The character is not valid. +**/ +BOOLEAN +IsValidFileNameChar ( + IN CONST CHAR16 Ch + ) +{ + // + // See if there are any illegal characters within the name + // + if (Ch < 0x20 || Ch == L'\"' || Ch == L'*' || Ch == L'/' || Ch == L'<' || Ch == L'>' || Ch == L'?' || Ch == L'|') { + return FALSE; + } + + return TRUE; +} + +/** + Check if file name has illegal characters. + + @param Name The filename to check. + + @retval TRUE The filename is ok. + @retval FALSE The filename is not ok. +**/ +BOOLEAN +IsValidFileName ( + IN CONST CHAR16 *Name + ) +{ + + UINTN Index; + UINTN Len; + + // + // check the length of Name + // + for (Len = 0, Index = StrLen (Name) - 1; Index + 1 != 0; Index--, Len++) { + if (Name[Index] == '\\' || Name[Index] == ':') { + break; + } + } + + if (Len == 0 || Len > 255) { + return FALSE; + } + // + // check whether any char in Name not appears in valid file name char + // + for (Index = 0; Index < StrLen (Name); Index++) { + if (!IsValidFileNameChar (Name[Index])) { + return FALSE; + } + } + + return TRUE; +} + +/** + Find a filename that is valid (not taken) with the given extension. + + @param[in] Extension The file extension. + + @retval NULL Something went wrong. + @return the valid filename. +**/ +CHAR16 * +EditGetDefaultFileName ( + IN CONST CHAR16 *Extension + ) +{ + EFI_STATUS Status; + UINTN Suffix; + CHAR16 *FileNameTmp; + + Suffix = 0; + + do { + FileNameTmp = CatSPrint (NULL, L"NewFile%d.%s", Suffix, Extension); + + // + // after that filename changed to path + // + Status = ShellFileExists (FileNameTmp); + + if (Status == EFI_NOT_FOUND) { + return FileNameTmp; + } + + FreePool (FileNameTmp); + FileNameTmp = NULL; + Suffix++; + } while (Suffix != 0); + + FreePool (FileNameTmp); + return NULL; +} + +/** + Read a file into an allocated buffer. The buffer is the responsibility + of the caller to free. + + @param[in] FileName The filename of the file to open. + @param[out] Buffer Upon successful return, the pointer to the + address of the allocated buffer. + @param[out] BufferSize If not NULL, then the pointer to the size + of the allocated buffer. + @param[out] ReadOnly Upon successful return TRUE if the file is + read only. FALSE otherwise. + + @retval EFI_NOT_FOUND The filename did not represent a file in the + file system. + @retval EFI_SUCCESS The file was read into the buffer. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR The file read operation failed. + @retval EFI_INVALID_PARAMETER A parameter was invalid. + @retval EFI_INVALID_PARAMETER FileName was NULL. + @retval EFI_INVALID_PARAMETER FileName was a directory. +**/ +EFI_STATUS +ReadFileIntoBuffer ( + IN CONST CHAR16 *FileName, + OUT VOID **Buffer, + OUT UINTN *BufferSize OPTIONAL, + OUT BOOLEAN *ReadOnly + ) +{ + VOID *InternalBuffer; + UINTN FileSize; + SHELL_FILE_HANDLE FileHandle; + BOOLEAN CreateFile; + EFI_STATUS Status; + EFI_FILE_INFO *Info; + + InternalBuffer = NULL; + FileSize = 0; + FileHandle = NULL; + CreateFile = FALSE; + Status = EFI_SUCCESS; + Info = NULL; + + if (FileName == NULL || Buffer == NULL || ReadOnly == NULL) { + return (EFI_INVALID_PARAMETER); + } + + // + // try to open the file + // + Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ, 0); + + if (!EFI_ERROR(Status)) { + ASSERT(CreateFile == FALSE); + if (FileHandle == NULL) { + return EFI_LOAD_ERROR; + } + + Info = ShellGetFileInfo(FileHandle); + + if (Info->Attribute & EFI_FILE_DIRECTORY) { + FreePool (Info); + return EFI_INVALID_PARAMETER; + } + + if (Info->Attribute & EFI_FILE_READ_ONLY) { + *ReadOnly = TRUE; + } else { + *ReadOnly = FALSE; + } + // + // get file size + // + FileSize = (UINTN) Info->FileSize; + + FreePool (Info); + } else if (Status == EFI_NOT_FOUND) { + // + // file not exists. add create and try again + // + Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0); + if (EFI_ERROR (Status)) { + return Status; + } else { + // + // it worked. now delete it and move on with the name (now validated) + // + Status = ShellDeleteFile (&FileHandle); + if (Status == EFI_WARN_DELETE_FAILURE) { + Status = EFI_ACCESS_DENIED; + } + if (EFI_ERROR (Status)) { + return Status; + } + } + // + // file doesn't exist, so set CreateFile to TRUE and can't be read-only + // + CreateFile = TRUE; + *ReadOnly = FALSE; + } + + // + // the file exists + // + if (!CreateFile) { + // + // allocate buffer to read file + // + InternalBuffer = AllocateZeroPool (FileSize); + if (InternalBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // read file into InternalBuffer + // + Status = ShellReadFile (FileHandle, &FileSize, InternalBuffer); + ShellCloseFile(&FileHandle); + FileHandle = NULL; + if (EFI_ERROR (Status)) { + SHELL_FREE_NON_NULL (InternalBuffer); + return EFI_LOAD_ERROR; + } + } + *Buffer = InternalBuffer; + if (BufferSize != NULL) { + *BufferSize = FileSize; + } + return (EFI_SUCCESS); + +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.h new file mode 100644 index 00000000..3f1ecee4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.h @@ -0,0 +1,377 @@ +/** @file + Main file for NULL named library for Profile1 shell command functions. + + Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _UEFI_SHELL_DEBUG1_COMMANDS_LIB_H_ +#define _UEFI_SHELL_DEBUG1_COMMANDS_LIB_H_ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +extern EFI_HII_HANDLE gShellDebug1HiiHandle; + +/** + Function returns a system configuration table that is stored in the + EFI System Table based on the provided GUID. + + @param[in] TableGuid A pointer to the table's GUID type. + @param[in, out] Table On exit, a pointer to a system configuration table. + + @retval EFI_SUCCESS A configuration table matching TableGuid was found. + @retval EFI_NOT_FOUND A configuration table matching TableGuid was not found. +**/ +EFI_STATUS +GetSystemConfigurationTable ( + IN EFI_GUID *TableGuid, + IN OUT VOID **Table + ); + +/** + Function for 'setsize' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunSetSize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'comp' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunComp ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'mode' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunMode ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'memmap' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunMemMap ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'compress' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunEfiCompress ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'decompress' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunEfiDecompress ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'dmem' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunDmem ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'loadpcirom' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunLoadPciRom ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'mm' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunMm ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'setvar' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunSetVar ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'sermode' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunSerMode ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'bcfg' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunBcfg ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'pci' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunPci ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'smbiosview' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunSmbiosView ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'dmpstore' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunDmpStore ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'dblk' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunDblk ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'edit' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunEdit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'hexedit' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunHexEdit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Clear the line at the specified Row. + + @param[in] Row The row number to be cleared ( start from 1 ) + @param[in] LastCol The last printable column. + @param[in] LastRow The last printable row. +**/ +VOID +EditorClearLine ( + IN UINTN Row, + IN UINTN LastCol, + IN UINTN LastRow + ); + +/** + Check if file name has illegal characters. + + @param Name The filename to check. + + @retval TRUE The filename is ok. + @retval FALSE The filename is not ok. +**/ +BOOLEAN +IsValidFileName ( + IN CONST CHAR16 *Name + ); + +/** + Find a filename that is valid (not taken) with the given extension. + + @param[in] Extension The file extension. + + @retval NULL Something went wrong. + @return the valid filename. +**/ +CHAR16 * +EditGetDefaultFileName ( + IN CONST CHAR16 *Extension + ); + +/** + Read a file into an allocated buffer. The buffer is the responsibility + of the caller to free. + + @param[in] FileName The filename of the file to open. + @param[out] Buffer Upon successful return, the pointer to the + address of the allocated buffer. + @param[out] BufferSize If not NULL, then the pointer to the size + of the allocated buffer. + @param[out] ReadOnly Upon successful return TRUE if the file is + read only. FALSE otherwise. + + @retval EFI_NOT_FOUND The filename did not represent a file in the + file system. Directories cannot be read with + this method. + @retval EFI_SUCCESS The file was read into the buffer. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR The file read operation failed. + @retval EFI_INVALID_PARAMETER A parameter was invalid. + @retval EFI_INVALID_PARAMETER FileName was NULL. + @retval EFI_INVALID_PARAMETER FileName was a directory. +**/ +EFI_STATUS +ReadFileIntoBuffer ( + IN CONST CHAR16 *FileName, + OUT VOID **Buffer, + OUT UINTN *BufferSize OPTIONAL, + OUT BOOLEAN *ReadOnly + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf new file mode 100644 index 00000000..9a4459e9 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf @@ -0,0 +1,132 @@ +## @file +# Provides shell Debug1 profile functions +# +# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiShellDebug1CommandsLib + FILE_GUID = 90330D51-A99B-4cc8-A2EB-AE22542A3F45 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.2 + LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = UefiShellDebug1CommandsLibConstructor + DESTRUCTOR = UefiShellDebug1CommandsLibDestructor + +[Sources] + SetSize.c + Comp.c + Mode.c + MemMap.c + Compress.h + Compress.c + EfiCompress.c + EfiDecompress.c + Dmem.c + LoadPciRom.c + Mm.c + SetVar.c + SerMode.c + Pci.c + Pci.h + DmpStore.c + Dblk.c + SmbiosView/EventLogInfo.c + SmbiosView/EventLogInfo.h + SmbiosView/PrintInfo.c + SmbiosView/QueryTable.c + SmbiosView/SmbiosView.c + SmbiosView/SmbiosViewStrings.uni + SmbiosView/LibSmbiosView.c + SmbiosView/PrintInfo.h + SmbiosView/LibSmbiosView.h + SmbiosView/QueryTable.h + SmbiosView/SmbiosView.h + UefiShellDebug1CommandsLib.c + UefiShellDebug1CommandsLib.h + UefiShellDebug1CommandsLib.uni + +## Files shared by both editors + EditTitleBar.h + EditTitleBar.c + EditInputBar.h + EditInputBar.c + EditStatusBar.h + EditStatusBar.c + EditMenuBar.h + EditMenuBar.c + +## Files specific to the text editor + Edit/Edit.c + Edit/TextEditor.h + Edit/TextEditorTypes.h + Edit/FileBuffer.h + Edit/FileBuffer.c + Edit/MainTextEditor.h + Edit/MainTextEditor.c + Edit/Misc.h + Edit/Misc.c + Edit/TextEditStrings.uni + +## Files specific to the HEX editor + HexEdit/BufferImage.h + HexEdit/BufferImage.c + HexEdit/Clipboard.h + HexEdit/Clipboard.c + HexEdit/DiskImage.h + HexEdit/DiskImage.c + HexEdit/FileImage.h + HexEdit/FileImage.c + HexEdit/HexEdit.c + HexEdit/HexEditor.h + HexEdit/HexEditorTypes.h + HexEdit/HexeditStrings.uni + HexEdit/MainHexEditor.h + HexEdit/MainHexEditor.c + HexEdit/MemImage.h + HexEdit/MemImage.c + HexEdit/Misc.h + HexEdit/Misc.c + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + BaseMemoryLib + IoLib + DebugLib + ShellCommandLib + ShellLib + UefiLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + SortLib + PrintLib + BcfgCommandLib + +[Pcd] + gEfiShellPkgTokenSpaceGuid.PcdShellFileOperationSize ## CONSUMES + gEfiShellPkgTokenSpaceGuid.PcdShellProfileMask ## CONSUMES + +[Protocols] + gEfiPciRootBridgeIoProtocolGuid ## SOMETIMES_CONSUMES + gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES + gEfiSimplePointerProtocolGuid ## SOMETIMES_CONSUMES + gEfiCpuIo2ProtocolGuid ## SOMETIMES_CONSUMES + +[Guids] + gEfiGlobalVariableGuid ## SOMETIMES_CONSUMES ## GUID + gEfiSmbiosTableGuid ## SOMETIMES_CONSUMES ## SystemTable + gEfiSmbios3TableGuid ## SOMETIMES_CONSUMES ## SystemTable + gEfiMpsTableGuid ## SOMETIMES_CONSUMES ## SystemTable + gEfiAcpi10TableGuid ## SOMETIMES_CONSUMES ## SystemTable + gEfiAcpi20TableGuid ## SOMETIMES_CONSUMES ## SystemTable + gShellDebug1HiiGuid ## SOMETIMES_CONSUMES ## HII diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.uni b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.uni new file mode 100644 index 00000000..6693be26 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.uni @@ -0,0 +1,1173 @@ +// /** +// +// Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+// (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
+// (C) Copyright 2016 - 2019 Hewlett Packard Enterprise Development LP
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// Module Name: +// +// UefiShellDebug1CommandsLib.uni +// +// Abstract: +// +// String definitions for UEFI Shell 2.0 Debug1 profile commands +// +// +// **/ + +/=# + +#langdef en-US "english" + +#string STR_GEN_NO_MEM #language en-US "%H%s%N: Memory is not available.\r\n" +#string STR_GEN_BOOT_ONLY #language en-US "%H%s%N: Boot must be selected for hot key options.\r\n" +#string STR_GEN_FIND_FAIL #language en-US "%H%s%N: File not found - '%H%s%N'\r\n" + +#string STR_GEN_PROBLEM #language en-US "%H%s%N: Unknown flag - '%H%s%N'\r\n" +#string STR_GEN_PROBLEM_VAL #language en-US "%H%s%N: Bad value - '%H%s%N' for flag - '%H%s%N'\r\n" +#string STR_GEN_DUPLICATE #language en-US "%H%s%N: Duplicate flag - '%H%s%N'\r\n" +#string STR_GEN_NO_VALUE #language en-US "%H%s%N: Missing argument for flag - '%H%s%N'\r\n" +#string STR_GEN_TOO_FEW #language en-US "%H%s%N: Too few arguments.\r\n" +#string STR_GEN_TOO_MANY #language en-US "%H%s%N: Too many arguments.\r\n" +#string STR_GEN_NO_DRIVER_BOOT #language en-US "%H%s%N: Driver or Boot must be selected.\r\n" +#string STR_GEN_PCIRBIO_NF #language en-US "%H%s%N: Protocol - PciRootBridgeIo not found.\r\n" +#string STR_GEN_PCIRBIO_ER #language en-US "%H%s%N: Problem accessing the data using Protocol - PciRootBridgeIo\r\n" +#string STR_GEN_PARAM_INV #language en-US "%H%s%N: Invalid argument - '%H%s%N'\r\n" +#string STR_GEN_PARAM_INV_HEX #language en-US "%H%s%N: Invalid parameter - '%H%s%N'. Must be hexadecimal.\r\n" +#string STR_GEN_PARAM_CONFLICT #language en-US "%H%s%N: Flags conflict with - '%H%s%N' and '%H%s%N'\r\n" +#string STR_GEN_OUT_MEM #language en-US "%H%s%N: Memory allocation was not successful.\r\n" +#string STR_GEN_MAP_PROTOCOL #language en-US "%H%s%N: Mapped device '%B%s%N' does not have protocol %B%s%N\r\n" +#string STR_GEN_FILE_OPEN_FAIL #language en-US "%H%s%N: Cannot open file - '%H%s%N'\r\n" +#string STR_GEN_FILE_DELETE_FAIL #language en-US "%H%s%N: Cannot delete file - '%H%s%N'\r\n" +#string STR_GEN_NO_CWD #language en-US "%H%s%N: Current directory not specified.\r\n" +#string STR_GEN_FILE_IS_DIRECTORY #language en-US "%H%s%N: The file '%H%s%N' is a directory.\r\n" +#string STR_GEN_SFO_HEADER #language en-US "ShellCommand,"%s"\r\n" + + +#string STR_FILE_OPEN_FAIL #language en-US "Unable to open file on '%B%s%N' with: %r.\r\n" +#string STR_FILE_FIND_FAIL #language en-US "%H%s%N: File not found - '%H%s%N'\r\n" +#string STR_FILE_NOT_DIR #language en-US "%H%s%N: Directories are not permitted - '%H%s%N'\r\n" +#string STR_SIZE_NOT_SPEC #language en-US "%H%s%N: A valid size must be specified\r\n" +#string STR_FILE_NOT_SPEC #language en-US "%H%s%N: File not specified\r\n" +#string STR_FILE_WRITE_FAIL #language en-US "%H%s%N: Write file error - '%H%s%N'\r\n" +#string STR_FILE_READ_FAIL #language en-US "%H%s%N: Read file error - '%H%s%N'\r\n" +#string STR_VOLUME_FULL #language en-US "%H%s%N: The volume is full\r\n" + +#string STR_SET_SIZE_FAIL #language en-US "%H%s%N: Unable to change size on '%B%s%N'\r\n" +#string STR_SET_SIZE_DONE #language en-US "Size changed on '%B%s%N'.\r\n" + +#string STR_DBLK_HEADER #language en-US "LBA %016LX Size %08x bytes BlkIo %0x\r\n" + +#string STR_COMP_HEADER #language en-US "Compare %s to %s.\r\n" +#string STR_COMP_DIFFERENCE_POINT #language en-US "Difference #% 2u:\r\n" +#string STR_COMP_END_OF_FILE #language en-US " " + +#string STR_COMP_FOOTER_FAIL #language en-US "[difference(s) encountered] \r\n" +#string STR_COMP_FOOTER_PASS #language en-US "[no differences encountered]\r\n" + +#string STR_MODE_SET_FAIL #language en-US "%H%s%N: Unable to change the mode.\r\n" +#string STR_MODE_NO_MATCH #language en-US "%H%s%N: No matching mode found to set\r\n" +#string STR_MODE_LIST_HEAD #language en-US "Available modes for console output device.\r\n" +#string STR_MODE_LIST_ITEM #language en-US " Col % 5d Row % 5d %c\r\n" + +#string STR_MEMMAP_GET_FAILED #language en-US "%H%s%N: Unable to get memory map\r\n" +#string STR_MEMMAP_LIST_HEAD #language en-US "Type Start End # Pages Attributes\r\n" +#string STR_MEMMAP_LIST_ITEM #language en-US "% -10s %016LX-%016LX %016LX %016LX\r\n" +#string STR_MEMMAP_LIST_ITEM_OTHER #language en-US "%08x %016LX-%016LX %016LX %016LX\r\n" +#string STR_MEMMAP_LIST_SUMM #language en-US " \r\n" + " Reserved : %,14ld Pages (%,ld Bytes)\r\n" + " LoaderCode: %,14ld Pages (%,ld Bytes)\r\n" + " LoaderData: %,14ld Pages (%,ld Bytes)\r\n" + " BS_Code : %,14ld Pages (%,ld Bytes)\r\n" + " BS_Data : %,14ld Pages (%,ld Bytes)\r\n" + " RT_Code : %,14ld Pages (%,ld Bytes)\r\n" + " RT_Data : %,14ld Pages (%,ld Bytes)\r\n" + " ACPI_Recl : %,14ld Pages (%,ld Bytes)\r\n" + " ACPI_NVS : %,14ld Pages (%,ld Bytes)\r\n" + " MMIO : %,14ld Pages (%,ld Bytes)\r\n" + " MMIO_Port : %,14ld Pages (%,ld Bytes)\r\n" + " PalCode : %,14ld Pages (%,ld Bytes)\r\n" + " Available : %,14ld Pages (%,ld Bytes)\r\n" + " Persistent: %,14ld Pages (%,ld Bytes)\r\n" +#string STR_MEMMAP_LIST_SUMM_OTHER #language en-US " %08x : %,14ld Pages (%,ld Bytes)\r\n" +#string STR_MEMMAP_LIST_SUMM2 #language en-US " -------------- \r\n" + "Total Memory: %,14ld MB (%,ld Bytes)\r\n" +#string STR_MEMMAP_LIST_ITEM_SFO #language en-US "MemoryMap,"%s","%LX","%LX","%LX","%LX"\r\n" +#string STR_MEMMAP_LIST_SUMM_SFO #language en-US "MemoryMapSummary,"%Ld","%Ld","%Ld","%Ld","%Ld","%Ld","%Ld","%Ld","%Ld","%Ld","%Ld","%Ld","%Ld","%Ld","%Ld","%Ld"\r\n" + +#string STR_EFI_COMPRESS_FAIL #language en-US "Unable to compress: %r.\r\n" +#string STR_EFI_DECOMPRESS_FAIL #language en-US "Unable to decompress: %r.\r\n" +#string STR_EFI_DECOMPRESS_NOPE #language en-US "The file does not appear to be a compressed file. Cannot continue. \"%H%s%N\"\r\n" + +#string STR_DMEM_HEADER_ROW #language en-US "Memory Address %016LX %X Bytes\r\n" +#string STR_DMEM_MMIO_HEADER_ROW #language en-US "Memory Mapped IO Address %016LX %X Bytes\r\n" +#string STR_DMEM_DATA_ROW #language en-US "%08X: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x *%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c*\r\n" +#string STR_DMEM_SYSTEM_TABLE #language en-US "\r\nValid EFI Header at Address %016Lx\r\n" + "---------------------------------------------\r\n" + "System: Table Structure size %08x revision %08x\r\n" + "ConIn (%016LX) ConOut (%016LX) StdErr (%016LX)\r\n" + "Runtime Services %016LX\r\n" + "Boot Services %016LX\r\n" + "SAL System Table %016LX\r\n" + "ACPI Table %016LX\r\n" + "ACPI 2.0 Table %016LX\r\n" + "MPS Table %016LX\r\n" + "SMBIOS Table %016LX\r\n" + +#string STR_LOAD_PCI_ROM_RES #language en-US "Image '%B%s%N' load result: %r\r\n" +#string STR_LOADPCIROM_CORRUPT #language en-US "%H%s%N: File '%B%s%N' Image %d is corrupt.\r\n" +#string STR_LOADPCIROM_LOAD_FAIL #language en-US "%H%s%N: File '%B%s%N' Image %d unable to load.\r\n" +#string STR_LOADPCIROM_START_FAIL #language en-US "%H%s%N: File '%B%s%N' Image %d unable to start.\r\n" + +#string STR_MM_NOT_ALIGNED #language en-US "%H%s%N: Address parameter %016LX is not aligned.\r\n" +#string STR_MM_PCIE_ADDRESS_RANGE #language en-US "%H%s%N: Address parameter %016LX is not a valid PCI/PCIE address.\r\n" +#string STR_MM_MMIO #language en-US "%HMMIO%N" +#string STR_MM_IO #language en-US "%HIO%N" +#string STR_MM_PCI #language en-US "%HPCI%N" +#string STR_MM_MEM #language en-US "%HMEM%N" +#string STR_MM_PCIE #language en-US "%HPCIE%N" +#string STR_MM_ADDRESS #language en-US " 0x%016lx : " +#string STR_MM_BUF #language en-US "0x%0*lx" +#string STR_MM_ERROR #language en-US "%H%s%N: Input had incorrect format\r\n" + +#string STR_SETVAR_PRINT #language en-US "%g - %s - %04x Bytes\r\n" +#string STR_SETVAR_ERROR_SET #language en-US "%H%s%N: Unable to set - %H%g%N - %H%s%N\r\n" +#string STR_SETVAR_ERROR_GET #language en-US "%H%s%N: Unable to get - %H%g%N - %H%s%N\r\n" +#string STR_SETVAR_ERROR_DPFT #language en-US "%H%s%N: DevicePathFromText conversion was not successful.\r\n" + +#string STR_SERMODE_NO_FOUND #language en-US "%H%s%N: No serial ports found.\r\n" +#string STR_SERMODE_NOT_FOUND #language en-US "%H%s%N: No serial port or specified serial port found.\r\n" +#string STR_SERMODE_BAD_HANDLE #language en-US "%H%s%N: Handle %H%02x%N is not a serial device handle.\r\n" +#string STR_SERMODE_SET_HANDLE #language en-US "Mode set on handle %H%02x%N successfully.\r\n" +#string STR_SERMODE_SET_FAIL #language en-US "%H%s%N: Mode change on handle %H%02x%N was not successful.\r\n" +#string STR_SERMODE_DISPLAY #language en-US "%x(%08x) - (%ld, %c, %d, %s)\r\n" +#string STR_SERMODE_SET_UNSUPPORTED #language en-US "%H%s%N: One or more of the new settings is not supported on handle %H%02x%N.\r\n" +#string STR_SERMODE_SET_DEV_ERROR #language en-US "%H%s%N: The serial device on handle %H%02x%N is not functioning correctly.\r\n" + +#string STR_PCI_HANDLE_CFG_ERR #language en-US "%H%s%N: Handle protocol or configuration error.\r\n" +#string STR_PCI_BUS_RANGE_ERR #language en-US "%H%s%N: Get next bus range error.\r\n" +#string STR_PCI_NO_FIND #language en-US "%H%s%N: Cannot find protocol interface for segment %x, bus %x.\r\n" +#string STR_PCI_NO_CFG #language en-US "%H%s%N: Cannot read configuration data.\r\n" +#string STR_PCI_INFO #language en-US "%H PCI Segment %02x Bus %02x Device %02x Func %02x%N [EFI %02x%02x%02x%02x00]\r\n" +#string STR_PCI_TITLE #language en-US " Seg Bus Dev Func\r\n" + " --- --- --- ----\r\n" +#string STR_PCI_LINE_P1 #language en-US " %E%02x %02x %02x %02x ==> %N" +#string STR_PCI_LINE_P2 #language en-US "\r\n Vendor %04x Device %04x Prog Interface %x\r\n" +#string STR_PCIEX_CAPABILITY_CAPID #language en-US "CapID(%2x): %E%02x%N" +#string STR_PCIEX_NEXTCAP_PTR #language en-US " NextCap Ptr(%2x): %E%02x%N\r\n" +#string STR_PCIEX_CAP_REGISTER #language en-US "Cap Register(%2x): %E%04x%N\r\n" +#string STR_PCIEX_DEVICE_CAP #language en-US "Device Capabilities(%2x): %E%08x%N\r\n" +#string STR_PCIEX_DEVICE_CONTROL #language en-US "Device Control(%2x): %E%04x%N\r\n" +#string STR_PCIEX_DEVICE_STATUS #language en-US "Device Status(%2x): %E%04x%N\r\n" +#string STR_PCIEX_LINK_CAPABILITIES #language en-US "Link Capabilities(%2x): %E%08x%N\r\n" +#string STR_PCIEX_LINK_CONTROL #language en-US "Link Control(%2x): %E%04x%N\r\n" +#string STR_PCIEX_LINK_STATUS #language en-US "Link Status(%2x): %E%04x%N\r\n" +#string STR_PCIEX_SLOT_CAPABILITIES #language en-US "Slot Capabilities(%2x): %E%08x%N\r\n" +#string STR_PCIEX_SLOT_CONTROL #language en-US "Slot Control(%2x): %E%04x%N\r\n" +#string STR_PCIEX_SLOT_STATUS #language en-US "Slot Status(%2x): %E%04x%N\r\n" +#string STR_PCIEX_ROOT_CONTROL #language en-US "Root Control(%2x): %E%04x%N\r\n" +#string STR_PCIEX_RSVDP #language en-US "Root Capabilities(%2x): %E%04x%N\r\n" +#string STR_PCIEX_ROOT_STATUS #language en-US "Root Status(%2x): %E%08x%N\r\n" +#string STR_PCI_LINE_VID_DID #language en-US "Vendor ID(%x): %E%04x%N Device ID(%x): %E%04x%N\r\n" +#string STR_PCI_LINE_RID #language en-US "Revision ID(%x): %E%02x%N " +#string STR_PCI_LINE_BIST #language en-US "BIST(%02x): " +#string STR_PCI_LINE_CAP #language en-US "Capable,Return: %E%02x%N\r\n" +#string STR_PCI_LINE_CAP_NO #language en-US " Incapable\r\n" +#string STR_PCI2_CACHE_LINE_SIZE #language en-US "Cache Line Size(%x): %E%02x%N " +#string STR_PCI2_LATENCY_TIMER #language en-US "Latency Timer(%x): %E%02x%N\r\n" +#string STR_PCI2_HEADER_TYPE #language en-US "Header Type(%02x): %E%02x%N, " +#string STR_PCI2_MULTI_FUNCTION #language en-US "Multi-function, " +#string STR_PCI2_SINGLE_FUNCTION #language en-US "Single function, " +#string STR_PCI2_PCI_DEVICE #language en-US "PCI device\r\n" +#string STR_PCI2_P2P_BRIDGE #language en-US "P2P bridge\r\n" +#string STR_PCI2_CARDBUS_BRIDGE #language en-US "CardBus bridge\r\n" +#string STR_PCI2_RESERVED #language en-US "Reserved\r\n" +#string STR_PCI2_CLASS #language en-US "Class: " +#string STR_PCI2_BASE_ADDR #language en-US "Base Address Registers(%x):\r\n" +#string STR_PCI2_START_TYPE #language en-US " Start_Address Type Space Prefetchable? Size Limit\r\n" +#string STR_PCI2_NONE #language en-US " (None)" +#string STR_PCI2_EXPANSION_ROM_DISABLED #language en-US "\r\nExpansion ROM Disabled(%x)\r\n\r\n" +#string STR_PCI2_EXPANSION_ROM_BASE #language en-US "\r\nExpansion ROM Base Address(%x): %E%08x%N\r\n\r\n" +#string STR_PCI2_CARDBUS_CIS #language en-US "Cardbus CIS ptr(%x): %E%08x%N\r\n" +#string STR_PCI2_SUB_VENDOR_ID #language en-US "Sub VendorID(%x): %E%04x%N " +#string STR_PCI2_SUBSYSTEM_ID #language en-US "Subsystem ID(%x): %E%04x%N\r\n" +#string STR_PCI2_CAPABILITIES_PTR #language en-US "Capabilities Ptr(%x): %E%02x%N\r\n" +#string STR_PCI2_INTERRUPT_LINE #language en-US "Interrupt Line(%x): %E%02x%N " +#string STR_PCI2_INTERRUPT_PIN #language en-US "Interrupt Pin(%x): %E%02x%N\r\n" +#string STR_PCI2_MIN_GNT #language en-US "Min_Gnt(%x): %E%02x%N " +#string STR_PCI2_MAX_LAT #language en-US "Max_Lat(%x): %E%02x%N\r\n" +#string STR_PCI2_BASE_ADDRESS #language en-US "Base Address Registers(%x):" +#string STR_PCI2_START_TYPE_2 #language en-US " Start_Address Type Space Prefetchable? Size Limit\r\n" +#string STR_PCI2_NO_EXPANSION_ROM #language en-US "\r\nNo Expansion ROM(%x) " +#string STR_PCI2_EXPANSION_ROM_BASE_2 #language en-US "\r\nExpansion ROM Base Address(%x): %E%08x%N\r\n" +#string STR_PCI2_BUS_NUMBERS #language en-US "\r\n\r\n(Bus Numbers) Primary(%x) Secondary(%x) Subordinate(%x)\r\n" +#string STR_PCI2_BRIDGE #language en-US " %E%02x%N" +#string STR_PCI2_SECONDARY_TIMER #language en-US "\r\nSecondary Latency Timer(%x): %E%02x%N\n\n" +#string STR_PCI2_CARDBUS_LATENCY #language en-US "\r\nCardBus Latency Timer(%x): %E%02x%N\r\n" +#string STR_PCI2_RESOURCE_TYPE_2 #language en-US "\r\nResource Type Type Base Limit\r\n" +#string STR_PCI2_MEM_3 #language en-US "Mem(%x) %s %E%08x%N %E%08x%N\r\n" +#string STR_PCI2_IO_2 #language en-US "I/O(%x) %s %E%08x%N %E%08x%N\r\n" +#string STR_PCI2_INTERRUPT_LINE_3 #language en-US "\r\nInterrupt Line(%x): %E%02x%N Interrupt Pin(%x): %E%02x%N\r\n" +#string STR_PCI2_SUB_VENDOR_ID_2 #language en-US "\r\nSub VendorID(%x): %E%04x%N Subsystem ID(%x): %E%04x%N\r\n" +#string STR_PCI2_OPTIONAL #language en-US "Optional 16-Bit PC Card legacy Mode Base Address(%x): %E%08x%N\r\n" +#string STR_PCI2_STATUS #language en-US "Status(%x): %E%04x%N\r\n" +#string STR_PCI2_SECONDARY_STATUS #language en-US "Secondary Status(%2x): %E%4x%N\r\n" +#string STR_PCI2_NEW_CAPABILITIES #language en-US " (04)New Capabilities linked list: %E%d%N" +#string STR_PCI2_66_CAPABLE #language en-US " (05)66MHz Capable: %EN/A%N\r\n" +#string STR_PCI2_66_CAPABLE_2 #language en-US " (05)66MHz Capable: %E%d%N\r\n" +#string STR_PCI2_FAST_BACK #language en-US " (07)Fast Back-to-Back Capable: %E%d%N" +#string STR_PCI2_NO #language en-US "No " +#string STR_PCI2_YES #language en-US "YES " +#string STR_PCI2_ONE_VAR_4 #language en-US "\r\n %E%04x%N " +#string STR_PCI2_NEWBAR_32 #language en-US " %08x " +#string STR_PCI2_NEWBAR_32_2 #language en-US " %08x" +#string STR_PCI2_RSHIFT #language en-US "%08x" +#string STR_PCI2_NEWBAR_32_3 #language en-US "%04x " +#string STR_PCI2_NEWBAR_32_4 #language en-US "%04x" +#string STR_PCI2_CARDBUS_SOCKET #language en-US "\r\nCardBus Socket Registers/ExCA Base Address Register(%x): %E%8x%N\r\n\r\n" +#string STR_PCI2_BUS_NUMBERS_2 #language en-US "\r\n(Bus Numbers) Pci(%x) CardBus(%x) Subordinate(%x)\r\n" +#string STR_PCI2_CARDBUS #language en-US " %E%02x%N" +#string STR_PCI2_CARDBUS_2 #language en-US " %E%02x%N" +#string STR_PCI2_CARDBUS_3 #language en-US " %E%02x%N\r\n" +#string STR_PCI2_MASTER_DATA #language en-US " (08)Master Data Parity Error: %E%d%N\r\n" +#string STR_PCI2_DEVSEL_TIMING #language en-US " (09)DEVSEL timing: " +#string STR_PCI2_FAST #language en-US "%E Fast%N" +#string STR_PCI2_MEDIUM #language en-US "%E Medium%N" +#string STR_PCI2_SLOW #language en-US "%E Slow%N" +#string STR_PCI2_RESERVED_2 #language en-US "%EReserved%N" +#string STR_PCI2_SIGNALED_TARGET #language en-US " (11)Signaled Target Abort: %E%d%N\r\n" +#string STR_PCI2_RECEIVED_TARGET #language en-US " (12)Received Target Abort: %E%d%N" +#string STR_PCI2_RECEIVED_MASTER #language en-US " (13)Received Master Abort: %E%d%N\r\n" +#string STR_PCI2_SIGNALED_ERROR #language en-US " (14)Signaled System Error: %E%d%N" +#string STR_PCI2_RECEIVED_ERROR #language en-US " (14)Received System Error: %E%d%N" +#string STR_PCI2_DETECTED_ERROR #language en-US " (15)Detected Parity Error: %E%d%N\r\n" +#string STR_PCI2_COMMAND #language en-US "Command(%x): %E%04x%N\r\n" +#string STR_PCI2_SPACE_ACCESS_DENIED #language en-US " (00)I/O space access enabled: %E%d%N" +#string STR_PCI2_MEMORY_SPACE #language en-US " (01)Memory space access enabled: %E%d%N\r\n" +#string STR_PCI2_BEHAVE_BUS_MASTER #language en-US " (02)Behave as bus master: %E%d%N" +#string STR_PCI2_MONITOR_SPECIAL_CYCLE #language en-US " (03)Monitor special cycle enabled: %E%d%N\r\n" +#string STR_PCI2_MEM_WRITE_INVALIDATE #language en-US " (04)Mem Write & Invalidate enabled: %E%d%N" +#string STR_PCI2_PALETTE_SNOOPING #language en-US " (05)Palette snooping is enabled: %E%d%N\r\n" +#string STR_PCI2_ASSERT_PERR #language en-US " (06)Assert PERR# when parity error: %E%d%N" +#string STR_PCI2_DO_ADDR_STEPPING #language en-US " (07)Do address/data stepping: %E%d%N\r\n" +#string STR_PCI2_SERR_DRIVER #language en-US " (08)SERR# driver enabled: %E%d%N" +#string STR_PCI2_FAST_BACK_2 #language en-US " (09)Fast back-to-back transact...: %E%d%N\r\n\r\n" +#string STR_PCI2_BRIDGE_CONTROL #language en-US "Bridge Control(%x) %E%04x%N\r\n" +#string STR_PCI2_PARITY_ERROR #language en-US " (00)Parity Error Response: %E%d%N" +#string STR_PCI2_SERR_ENABLE #language en-US " (01)SERR# Enable: %E%d%N\r\n" +#string STR_PCI2_ISA_ENABLE #language en-US " (02)ISA Enable: %E%d%N" +#string STR_PCI2_RESOURCE_TYPE #language en-US "\r\nResource Type Base Limit\r\n" +#string STR_PCI2_TWO_VARS #language en-US "I/O(%x) %E%08x%N" +#string STR_PCI2_ONE_VAR #language en-US " %E%08x%N\r\n" +#string STR_PCI2_MEMORY #language en-US "Memory(%x) %E%08x%N" +#string STR_PCI2_PREFETCHABLE #language en-US "Prefetchable Memory(%x) %E%08x%08x%N" +#string STR_PCI2_TWO_VARS_2 #language en-US " %E%08x%08x%N\r\n" +#string STR_PCI2_CAPABILITIES_PTR_2 #language en-US "\r\nCapabilities Ptr(%x): %E%02x%N \r\n\r\n" +#string STR_PCI2_INTERRUPT_LINE_2 #language en-US "\r\nInterrupt Line(%x) %E%02x%N " +#string STR_PCI2_BAR #language en-US "\r\n %E%08x%N " +#string STR_PCI2_MEM #language en-US "Mem " +#string STR_PCI2_32_BITS #language en-US "32 bits " +#string STR_PCI2_ONE_VAR_2 #language en-US "\r\n %E%08x" +#string STR_PCI2_ONE_VAR_3 #language en-US "%08x%N " +#string STR_PCI2_64_BITS #language en-US "64 bits " +#string STR_PCI2_MEM_2 #language en-US "Mem " +#string STR_PCI2_VGA_ENABLE #language en-US " (03)VGA Enable: %E%d%N\r\n" +#string STR_PCI2_MASTER_ABORT #language en-US " (05)Master Abort Mode: %E%d%N" +#string STR_PCI2_SECONDARY_BUS_RESET #language en-US " (06)Secondary Bus Reset: %E%d%N\r\n" +#string STR_PCI2_FAST_ENABLE #language en-US " (07)Fast Back-to-Back Enable: %E%d%N" +#string STR_PCI2_PRIMARY_DISCARD_TIMER #language en-US " (08)Primary Discard Timer: %E%s%N\r\n" +#string STR_PCI2_SECONDARY_DISCARD_TIMER #language en-US " (09)Secondary Discard Timer: %E%s%N" +#string STR_PCI2_DISCARD_TIMER_STATUS #language en-US " (10)Discard Timer Status: %E%d%N\r\n" +#string STR_PCI2_DISCARD_TIMER_SERR #language en-US " (11)Discard Timer SERR# Enable: %E%d%N\r\n" +#string STR_PCI2_CARDBUS_RESET #language en-US " (06)CardBus Reset: %E%d%N\r\n" +#string STR_PCI2_IREQ_ENABLE #language en-US " (07)IREQ/INT Enable: %E%d%N" +#string STR_PCI2_WRITE_POSTING_ENABLE #language en-US " (10)Write Posting Enable: %E%d%N\r\n" +#string STR_PCI_EXT_CAP_AER #language en-US " Advanced Error Reporting\r\n" + " UncorrectableErrorStatus %08x\r\n" + " UncorrectableErrorMask %08x\r\n" + " UncorrectableErrorSeverity %08x\r\n" + " CorrectableErrorStatus %08x\r\n" + " CorrectableErrorMask %08x\r\n" + " AdvancedErrorCapAndControl %08x\r\n" + " HeaderLog1 %08x\r\n" + " HeaderLog2 %08x\r\n" + " HeaderLog3 %08x\r\n" + " HeaderLog4 %08x\r\n" + " RootErrorCommand %08x\r\n" + " RootErrorStatus %08x\r\n" + " ErrorSourceIdentification %04x\r\n" + " CorrectableErrorSourceIden %04x\r\n" + " TlpPrefixLog1 %08x\r\n" + " TlpPrefixLog2 %08x\r\n" + " TlpPrefixLog3 %08x\r\n" + " TlpPrefixLog4 %08x\r\n" +#string STR_PCI_EXT_CAP_LINK_CONTROL #language en-US " Link Control\r\n" + " RootComplexLinkCapabilities %08x\r\n" + " RootComplexLinkControl %04x\r\n" + " RootComplexLinkStatus %04x\r\n" +#string STR_PCI_EXT_CAP_LINK_DECLAR #language en-US " Link Declaration\r\n" + " ElementSelfDescription %08x\r\n" +#string STR_PCI_EXT_CAP_LINK_DECLAR2 #language en-US " LinkEntry[%x] %08x\r\n" +#string STR_PCI_EXT_CAP_SN #language en-US " Serial Number\r\n" + " SerialNumber %L16x\r\n" +#string STR_PCI_EXT_CAP_POWER #language en-US " Power Budgeting\r\n" + " DataSelect %02x\r\n" + " Data %08x\r\n" + " PowerBudgetCapability %02x\r\n" +#string STR_PCI_EXT_CAP_ACS #language en-US " ACS\r\n" + " CapabilityRegister %04x\r\n" + " ControlRegister %04x\r\n" +#string STR_PCI_EXT_CAP_ACS2 #language en-US " EgressControlVectorByte[%x] %02x\r\n" +#string STR_PCI_EXT_CAP_LAT #language en-US " Latency Tolerance Reporting\r\n" + " MaxSnoopLatency %04x\r\n" + " MaxNoSnoopLatency %04x\r\n" +#string STR_PCI_EXT_CAP_ARI #language en-US " ARI\r\n" + " AriCapability %04x\r\n" + " AriControl %04x\r\n" +#string STR_PCI_EXT_CAP_RCRB #language en-US " RCRB\r\n" + " VendorId %04x\r\n" + " DeviceId %04x\r\n" + " RcrbCapabilities %04x\r\n" + " RcrbControl %04x\r\n" +#string STR_PCI_EXT_CAP_VEN #language en-US " VendorSpecific\r\n" + " VendorSpecificHeader %04x\r\n" +#string STR_PCI_EXT_CAP_DPA #language en-US " DPA\r\n" + " DpaCapability %04x\r\n" + " DpaLatencyIndicator %04x\r\n" + " DpaStatus %04x\r\n" + " DpaControl %04x\r\n" +#string STR_PCI_EXT_CAP_DPA2 #language en-US " DpaPowerAllocationArray[%x] %02x\r\n" +#string STR_PCI_EXT_CAP_ECEA #language en-US " Event Collector Endpoint Association\r\n" + " AssociationBitmap %04x\r\n" +#string STR_PCI_EXT_CAP_VC_BASE #language en-US " Virtual (Multi) Channel Capability\r\n" + " ExtendedVcCount %08x\r\n" + " PortCapability1 %08x\r\n" + " PortCapability2 %08x\r\n" + " ArbitrationTableOffset %08x\r\n" + " PortVcControl %04x\r\n" + " PortVcStatus %04x\r\n" +#string STR_PCI_EXT_CAP_VC_ITEM #language en-US " Virtual Channel Capability Extended Item[%x]\r\n" + " ResourceCapability %08x\r\n" + " ArbitrationTableOffset %08x\r\n" + " ResourceControl %08x\r\n" + " ResourceStatus %04x\r\n" +#string STR_PCI_EXT_CAP_MULTICAST #language en-US " MultiCast Capability\r\n" + " MultiCastCapability %04x\r\n" + " MulticastControl %04x\r\n" + " McBaseAddress %L16x\r\n" + " McReceiveAddress %L16x\r\n" + " McBlockAll %L16x\r\n" + " McBlockUntranslated %L16x\r\n" + " McOverlayBar %L16x\r\n" +#string STR_PCI_EXT_CAP_RESIZE_BAR #language en-US " Resizeable Bar Capability [%x]\r\n" + " ResizableBarCapability %08x\r\n" + " ResizableBarControl %04x\r\n" +#string STR_PCI_EXT_CAP_TPH #language en-US " TPH\r\n" + " TphRequesterCapability %08x\r\n" + " TphRequesterControl %04x\r\n" + " TphTable (optional):\r\n" +#string STR_PCI_EXT_CAP_SECONDARY #language en-US " Secondary PCI Express Extended Capability\r\n" + " LinkControl3 %08x\r\n" + " LaneErrorStatus %08x\r\n" + " EqualizationControl:\r\n" + +#string STR_DMPSTORE_SAVE #language en-US "Save variable to file: %H%s%N.\r\n" +#string STR_DMPSTORE_LOAD #language en-US "Load and set variables from file: %H%s%N.\r\n" +#string STR_DMPSTORE_LOAD_GEN_FAIL #language en-US "%H%s%N: Failed to set variable %H%s%N: %r.\r\n" +#string STR_DMPSTORE_LOAD_BAD_FILE #language en-US "%H%s%N: Incorrect file format.\r\n" +#string STR_DMPSTORE_HEADER_LINE #language en-US "Variable %H%s%N '%H%g%N:%H%s%N' DataSize = 0x%02x\r\n" +#string STR_DMPSTORE_HEADER_LINE2 #language en-US "Variable %H%s%N '%H%s%N:%H%s%N' DataSize = 0x%02x\r\n" +#string STR_DMPSTORE_DELETE_LINE #language en-US "Delete variable '%H%g%N:%H%s%N': %r\r\n" +#string STR_DMPSTORE_NO_VAR_FOUND #language en-US "%H%s%N: No matching variables found.\r\n" +#string STR_DMPSTORE_NO_VAR_FOUND_SFO #language en-US "VariableInfo,\"\",\"\",\"\",\"\",\"\"\r\n" +#string STR_DMPSTORE_NO_VAR_FOUND_GN #language en-US "%H%s%N: No matching variables found. Guid %g, Name %s\r\n" +#string STR_DMPSTORE_NO_VAR_FOUND_NG_SFO #language en-US "VariableInfo,\"%s\",\"%g\",\"\",\"\",\"\"\r\n" +#string STR_DMPSTORE_NO_VAR_FOUND_N #language en-US "%H%s%N: No matching variables found. Name %s\r\n" +#string STR_DMPSTORE_NO_VAR_FOUND_N_SFO #language en-US #language en-US "VariableInfo,\"%s\",\"\",\"\",\"\",\"\"\r\n" +#string STR_DMPSTORE_NO_VAR_FOUND_G #language en-US "%H%s%N: No matching variables found. Guid %g\r\n" +#string STR_DMPSTORE_NO_VAR_FOUND_G_SFO #language en-US "VariableInfo,\"\",\"%g\",\"\",\"\",\"\"\r\n" +#string STR_DMPSTORE_VAR_SFO #language en-US "VariableInfo,\"%s\",\"%g\",\"0x%x\",\"0x%x\",\"%s\"\r\n" + +#string STR_GET_HELP_COMP #language en-US "" +".TH comp 0 "Compare 2 files"\r\n" +".SH NAME\r\n" +"Compares the contents of two files on a byte-for-byte basis.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"COMP [-b] file1 file2\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -b - Displays one screen at a time.\r\n" +" file1 - Specifies a first file name (directory name or wildcards not permitted).\r\n" +" file2 - Specifies a second file name (directory name or wildcards not permitted).\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command compares the contents of two files in binary mode.\r\n" +" 2. It displays up to 10 differences between the two files. For each\r\n" +" difference, up to 32 bytes from the location where the difference starts\r\n" +" is dumped.\r\n" +" 3. It will exit immediately if the lengths of the compared files are\r\n" +" different.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To compare two files with the same length but different contents:\r\n" +" fs0:\> comp bios.inf bios2.inf\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The function operated as expected.\r\n" +" SHELL_NOT_EQUAL The files were not identical.\r\n" +" SHELL_INVALID_PARAMETER One of the passed in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_NOT_FOUND The requested file was not found.\r\n" + +#string STR_GET_HELP_SETSIZE #language en-US "" +".TH setsize 0 "Set file size"\r\n" +".SH NAME\r\n" +"Adjusts the size of a file.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"SETSIZE size file [file...]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" size - Specifies the size of the file after it is adjusted.\r\n" +" file - Specifies the file or files to be adjusted.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. Setting the size smaller than the actual data contained in this file will\r\n" +" truncate its data.\r\n" +" 2. This command adjusts the size of a particular target file.\r\n" +" 3. This command automatically truncates or extends the size of a file based on the passed-in\r\n" +" parameters. If the file does not exist, it is created.\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_VOLUME_FULL The media has insufficient space to complete the\r\n" +" request.\r\n" +" SHELL_INVALID_PARAMETER One of the passed in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" + +#string STR_GET_HELP_MODE #language en-US "" +".TH mode 0 "Shows or changes ConOut mode."\r\n" +".SH NAME\r\n" +"Displays or changes the console output device mode.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"MODE [col row]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" col - Specifies the number of columns.\r\n" +" row - Specifies the number of rows.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command changes the display mode for the console output\r\n" +" device.\r\n" +" 2. When this command is used without any parameters, it shows the list of\r\n" +" modes that the standard output device currently supports.\r\n" +" 3. When used with the row and col parameter, this command\r\n" +" changes the number of rows and columns on the standard output device.\r\n" +" 4. The current selected mode is indicated by a '*'. \r\n" +" 5. The display is cleared every time this command is used to change the\r\n" +" currently selected display mode.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display all available modes on standard output:\r\n" +" Shell> mode\r\n" +" \r\n" +" * To change the current mode setting:\r\n" +" Shell> mode 80 50\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_INVALID_PARAMETER One of the passed-in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" + +#string STR_GET_HELP_MEMMAP #language en-US "" +".TH memmap 0 "Displays the memory map."\r\n" +".SH NAME\r\n" +"Displays the memory map maintained by the UEFI environment.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"MEMMAP [-b] [-sfo]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -b - Displays one screen at a time\r\n" +" -sfo - Displays information as described in Standard-Format Output.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. The UEFI environment keeps track of all the physical memory in the system\r\n" +" and how it is currently being used.\r\n" +" 2. Total Memory is the physical memory size excluding Reserved, Unusable,\r\n" +" MemoryMappedIO, and MemoryMappedIOPortSpace memory types.\r\n" +" 3. Refer to the UEFI specification for memory type definitions.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display the system memory map:\r\n" +" Shell> memmap\r\n" +" \r\n" + +#string STR_GET_HELP_EFICOMPRESS #language en-US "" +".TH eficompress 0 "compresses a file."\r\n" +".SH NAME\r\n" +"Compresses a file using UEFI Compression Algorithm.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"EFICOMPRESS infile outfile\r\n" +".SH OPTIONS\r\n" +" \r\n" +" infile - Specifies the file name of the uncompressed input file.\r\n" +" outfile - Specifies the file name of the compressed output file.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command compresses a file using UEFI Compression Algorithm\r\n" +" and writes the compressed form out to a new file.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To compress a file named 'uncompressed' to a file named 'compressed':\r\n" +" fs0:\> eficompress uncompressed compressed\r\n" + +#string STR_GET_HELP_EFIDCOMPRESS #language en-US "" +".TH efidecompress 0 "Decompresses a file."\r\n" +".SH NAME\r\n" +"Decompresses a file using UEFI Decompression Algorithm.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"EFIDECOMPRESS infile outfile\r\n" +".SH OPTIONS\r\n" +" \r\n" +" infile - Specifies the file name of the compressed input file.\r\n" +" outfile - Specifies the file name of the decompressed output file.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This decompresses a file using UEFI Decompression\r\n" +" Algorithm and writes the decompressed form out to a new file.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To decompress a file named 'compressed' to a file named 'uncompressed':\r\n" +" fs0:\> efidecompress compressed uncompressed\r\n" + +#string STR_GET_HELP_DMEM #language en-US "" +".TH dmem 0 "Displays memory."\r\n" +".SH NAME\r\n" +"Displays the contents of system or device memory.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"DMEM [-b] [address] [size] [-MMIO]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -b - Displays one screen at a time.\r\n" +" -MMIO - Forces address cycles to the PCI bus.\r\n" +" address - Specifies a starting address in hexadecimal format.\r\n" +" size - Specifies the number of bytes to display in hexadecimal format.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command displays the contents of system memory or device memory.\r\n" +" 2. Enter address and size in hexadecimal format.\r\n" +" 3. If address is not specified, the contents of the UEFI System Table\r\n" +" are displayed. Otherwise, memory starting at the specified address is displayed.\r\n" +" 4. Size specifies the number of bytes to display. If size is not specified,\r\n" +" 512 bytes are displayed.\r\n" +" 5. If MMIO is not specified, main system memory is displayed. Otherwise,\r\n" +" device memory is displayed through the use of the\r\n" +" EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display the UEFI system table pointer entries:\r\n" +" fs0:\> dmem\r\n" +" \r\n" +" * To display memory contents from 1af3088 with size of 16 bytes:\r\n" +" Shell> dmem 1af3088 16\r\n" +" \r\n" +" * To display memory mapped IO contents from 1af3088 with a size of 16 bytes:\r\n" +" Shell> dmem 1af3088 16 -MMIO\r\n" + +#string STR_GET_HELP_MM #language en-US "" +".TH mm 0 "Displays or modifies address space memory."\r\n" +".SH NAME\r\n" +"Displays or modifies MEM/MMIO/IO/PCI/PCIE address space.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"MM Address [Value] [-w 1|2|4|8] [-MEM | -MMIO | -IO | -PCI | -PCIE] [-n]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" Address - Starting address in hexadecimal format.\r\n" +" Value - The value to write in hexadecimal format.\r\n" +" -MEM - Memory Address type\r\n" +" -MMIO - Memory Mapped IO Address type\r\n" +" -IO - IO Address type\r\n" +" -PCI - PCI Configuration Space Address type:\r\n" +" Address format: ssssbbddffrr\r\n" +" ssss - Segment\r\n" +" bb - Bus\r\n" +" dd - Device\r\n" +" ff - Function\r\n" +" rr - Register\r\n" +" -PCIE - PCIE Configuration Space Address type:\r\n" +" Address format: ssssbbddffrrr\r\n" +" ssss - Segment\r\n" +" bb - Bus\r\n" +" dd - Device\r\n" +" ff - Function\r\n" +" rrr - Register\r\n" +" -w - Unit size accessed in bytes:\r\n" +" 1 - 1 byte\r\n" +" 2 - 2 bytes\r\n" +" 4 - 4 bytes\r\n" +" 8 - 8 bytes\r\n" +" -n - Non-interactive mode\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. If the address type parameter is not specified, address type defaults\r\n" +" to the 'MEM' type.\r\n" +" 2. If the 'Value' parameter is specified, the '-n' option is used and\r\n" +" the command writes the value to the\r\n" +" specified address in non-interactive mode. If the 'Value' parameter is\r\n" +" not specified, only the current contents in the address are displayed.\r\n" +" 3. If the '-w' option is not specified, unit size defaults to 1 byte.\r\n" +" 4. If the PCI address type is specified, the 'Address' parameter must\r\n" +" follow the PCI Configuration Space Address format above. The 'PCI'\r\n" +" command can be used to determine the address for a specified device.\r\n" +" It is listed in the PCI configuration space dump information in the\r\n" +" following format: "[EFI ssbbddffxx]".\r\n" +" 5. If the PCIE address type is specified, the 'Address' parameter must\r\n" +" follow the PCIE Configuration Space Address format above.\r\n" +" 6. In interactive mode, type a hex value to modify, 'q' or '.' to exit.\r\n" +" If the '-n' option is specified, it runs in non-interactive mode,\r\n" +" which supports batch file operation without user intervention.\r\n" +" 7. Not all PCI configuration register locations are writable.\r\n" +" 8. MM will only write the specified value. Read-modify-write operations\r\n" +" are not supported.\r\n" +" 9. The 'Address' parameter must be aligned on a boundary of the\r\n" +" specified width.\r\n" +" 10. Not all addresses are safe to access. Access to any improper address\r\n" +" can bring unexpected results.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display or modify memory:\r\n" +" Address 0x1b07288, default width=1 byte:\r\n" +" fs0:\> mm 1b07288\r\n" +" MEM 0x0000000001B07288 : 0x6D >\r\n" +" MEM 0x0000000001B07289 : 0x6D >\r\n" +" MEM 0x0000000001B0728A : 0x61 > 80\r\n" +" MEM 0x0000000001B0728B : 0x70 > q\r\n" +" fs0:\> mm 1b07288\r\n" +" MEM 0x0000000001B07288 : 0x6D >\r\n" +" MEM 0x0000000001B07289 : 0x6D >\r\n" +" MEM 0x0000000001B0728A : 0x80 > *Modified\r\n" +" MEM 0x0000000001B0728B : 0x70 > q\r\n" +" \r\n" +" * To modify memory: Address 0x1b07288, width = 2 bytes:\r\n" +" Shell> mm 1b07288 -w 2\r\n" +" MEM 0x0000000001B07288 : 0x6D6D >\r\n" +" MEM 0x0000000001B0728A : 0x7061 > 55aa\r\n" +" MEM 0x0000000001B0728C : 0x358C > q\r\n" +" Shell> mm 1b07288 -w 2\r\n" +" MEM 0x0000000001B07288 : 0x6D6D >\r\n" +" MEM 0x0000000001B0728A : 0x55AA > *Modified\r\n" +" MEM 0x0000000001B0728C : 0x358C > q\r\n" +" \r\n" +" * To display IO space: Address 80h, width = 4 bytes:\r\n" +" Shell> mm 80 -w 4 -IO\r\n" +" IO 0x0000000000000080 : 0x000000FE >\r\n" +" IO 0x0000000000000084 : 0x00FF5E6D > q\r\n" +" \r\n" +" * To modify IO space using non-interactive mode:\r\n" +" Shell> mm 80 52 -w 1 -IO\r\n" +" Shell> mm 80 -w 1 -IO\r\n" +" IO 0x0000000000000080 : 0x52 > FE *Modified\r\n" +" IO 0x0000000000000081 : 0xFF >\r\n" +" IO 0x0000000000000082 : 0x00 >\r\n" +" IO 0x0000000000000083 : 0x00 >\r\n" +" IO 0x0000000000000084 : 0x6D >\r\n" +" IO 0x0000000000000085 : 0x5E >\r\n" +" IO 0x0000000000000086 : 0xFF >\r\n" +" IO 0x0000000000000087 : 0x00 > q\r\n" +" \r\n" +" * To display PCI configuration space, ss=0000, bb=00, dd=00, ff=00, rr=00:\r\n" +" Shell> mm 000000000000 -PCI\r\n" +" PCI 0x0000000000000000 : 0x86 >\r\n" +" PCI 0x0000000000000001 : 0x80 >\r\n" +" PCI 0x0000000000000002 : 0x30 >\r\n" +" PCI 0x0000000000000003 : 0x11 >\r\n" +" PCI 0x0000000000000004 : 0x06 >\r\n" +" PCI 0x0000000000000005 : 0x00 > q\r\n" +" These contents can also be displayed by 'PCI 00 00 00'.\r\n" +" \r\n" +" * To display PCIE configuration space, ss=0000, bb=06, dd=00, ff=00, rrr=000:\r\n" +" Shell> mm 0000060000000 -PCIE\r\n" +" PCIE 0x0000000060000000 : 0xAB >\r\n" +" PCIE 0x0000000060000001 : 0x11 >\r\n" +" PCIE 0x0000000060000002 : 0x61 >\r\n" +" PCIE 0x0000000060000003 : 0x43 >\r\n" +" \r\n" + +#string STR_GET_HELP_LOAD_PCI_ROM #language en-US "" +".TH loadpcirom 0 "Loads a PCI option ROM file."\r\n" +".SH NAME\r\n" +"Loads a PCI Option ROM.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"LoadPciRom [-nc] romfile [romfile...]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -nc - Loads the ROM image(s) but does not connect drivers.\r\n" +" romfile - Specifies the PCI option ROM image file (wildcards are permitted).\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command loads PCI option ROM images into memory for\r\n" +" execution.\r\n" +" 2. The file can contain legacy images and multiple PE32 images, in which case\r\n" +" all PE32 images are loaded.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To load a rom file 'rom.bin':\r\n" +" fs0:\> LoadPciRom rom.bin\r\n" +" \r\n" +" * To load '*.bin' files without connecting drivers:\r\n" +" fs0:\> LoadPciRom -nc *.bin\r\n" + +#string STR_GET_HELP_SETVAR #language en-US "" +".TH setvar 0 "Displays or modifies a UEFI variable."\r\n" +".SH NAME\r\n" +"Displays or modifies a UEFI variable.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"SETVAR variable-name [-guid guid][-bs][-rt][-nv] [=data]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" variable-name - Specifies the name of the UEFI variable to modify or display.\r\n" +" -guid - Specifies the GUID of the UEFI variable to modify or display.\r\n" +" If not present, GUID EFI_GLOBAL_VARIABLE is assumed.\r\n" +" -bs - Indicates that the variable is a boot variable. Applies to a new variable;\r\n" +" otherwise, it is ignored. \r\n" +" -rt - Indicates that the variable is a runtime variable. Applies to a new variable;\r\n" +" otherwise, it is ignored. \r\n" +" -nv - Indicates that the variable is non-volatile. If not present,\r\n" +" then the variable is assumed to be volatile. Applies to a new variable;\r\n" +" otherwise, it is ignored. \r\n" +" =data - Specifies there is new data for the variable. If there is nothing after the '='\r\n" +" then the variable is deleted. If '=' is not present, then the\r\n" +" current value of the variable is dumped as hex bytes.\r\n" +" The data can consist of zero or more of the following:\r\n" +" xx[xx] - Hexadecimal bytes\r\n" +" ^"ascii-string^" - ASCII-string with no null-terminator\r\n" +" L^"UCS2-string^" - UCS-2 encoded string with no\r\n" +" null-terminator\r\n" +" --device - Device path text format\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command changes the UEFI variable specified by name and GUID.\r\n" +" 2. If = is specified, but data is not, the variable is deleted, if it exists.\r\n" +" 3. If = is not specified, then the current variable contents are displayed.\r\n" +" 4. If =data is specified, then the variable's value is changed to the value\r\n" +" specified by data.\r\n" +" 5. -bs, -rt and -nv are only useful if the variable does not exist.\r\n" +" 6. If the variable already exists, the attributes cannot be changed, and the" +" flags will be ignored.\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The shell has stored the variable and its data with\r\n" +" the defined attributes.\r\n" +" SHELL_INVALID_PARAMETER Incorrect attributes were used.\r\n" +" SHELL_OUT_OF_RESOURCES Insufficient resources were available for storing\r\n" +" the variable and its data.\r\n" +" SHELL_DEVICE_ERROR The Variable could not be saved due to a hardware\r\n" +" error.\r\n" +" SHELL_WRITE_PROTECTED The variable in question is read-only.\r\n" +" SHELL_WRITE_PROTECTED The variable in question cannot be deleted.\r\n" +" SHELL_NOT_FOUND The variable could not be found.\r\n" + +#string STR_GET_HELP_SERMODE #language en-US "" +".TH sermode 0 "configure serial port"\r\n" +".SH NAME\r\n" +"Sets serial port attributes.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"SERMODE [handle [baudrate parity databits stopbits]]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" handle - Specifies a device handle for a serial port in hexadecimal format.\r\n" +" baudrate - Specifies a baud rate for specified serial port.\r\n" +" parity - Sets parity bit settings for specified serial port. Valid values\r\n" +" are:\r\n" +" d - Default parity\r\n" +" n - No parity\r\n" +" e - Even parity\r\n" +" o - Odd parity\r\n" +" m - Mark parity\r\n" +" s - Space parity\r\n" +" databits - Sets the data bits for the specified serial port.\r\n" +" stopbits - Sets the stop bits for the specified serial port.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. The 'handle' parameter is the device handle of the desired serial port.\r\n" +" The 'DH' command can be used to retrieve this information.\r\n" +" 2. The 'stopbits' parameter supports the following settings:\r\n" +" 0 (0 stop bits - default setting)\r\n" +" 1 (1 stop bit)\r\n" +" 2 (2 stop bits)\r\n" +" 15 (1.5 stop bits)\r\n" +" All other settings are invalid.\r\n" +" 3. The 'baudrate' parameter supports the following settings:\r\n" +" 50, 75, 110, 150, 300, 600, 1200, 1800, 2000, 2400, 3600, 4800,\r\n" +" 7200, 9600(default), 19200, 38400, 57600, 115200, 230400, 460800\r\n" +" All other values will be converted to the next highest setting.\r\n" +" 4. The 'databits' parameter supports the following settings:\r\n" +" 4\r\n" +" 7\r\n" +" 8 (default)\r\n" +" All other settings are invalid.\r\n" +" 5. Parity attributes are mutually exclusive.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display the settings for all serial port devices:\r\n" +" Shell> sermode\r\n" +" \r\n" +" * To display the settings for the serial port device whose handle is 0x6B:\r\n" +" Shell> sermode 6B\r\n" +" \r\n" +" * To configure the serial port settings for handle 0x6B to 9600bps, even\r\n" +" parity, 8 data bits, and 1 stop bit:\r\n" +" Shell> sermode 6B 9600 e 8 1\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The new attributes were set on the serial device.\r\n" +" SHELL_INVALID_PARAMETER One or more of the attributes has an unsupported\r\n" +" value.\r\n" +" SHELL_DEVICE_ERROR The serial device is not functioning correctly.\r\n" + +#string STR_GET_HELP_PCI #language en-US "" +".TH pci 0 "Displays PCI device information."\r\n" +".SH NAME\r\n" +"Displays PCI device list or PCI function configuration space and PCIe extended\r\n" +"configuration space.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"PCI [Bus Dev [Func] [-s Seg] [-i [-ec ID]]]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -s - Specifies optional segment number (hexadecimal number).\r\n" +" -i - Displays interpreted information.\r\n" +" -ec - Displays detailed interpretation of specified PCIe extended capability\r\n" +" ID (hexadecimal number).\r\n" +" Bus - Specifies a bus number (hexadecimal number).\r\n" +" Dev - Specifies a device number (hexadecimal number).\r\n" +" Func - Specifies a function number (hexadecimal number).\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command displays a list of all the PCI devices found in the system. It\r\n" +" also displays the configuration space of a PCI device according to the\r\n" +" specified bus (Bus), device (Dev), and function (Func) addresses. If the\r\n" +" function address is not specified, it defaults to 0.\r\n" +" 2. The -i option displays verbose information for the specified PCI\r\n" +" device. The PCI configuration space for the device is displayed with\r\n" +" a detailed interpretation.\r\n" +" 3. If no parameters are specified, all PCI devices are listed.\r\n" +" 4. If the 'Bus' and 'Dev' parameters are specified but the 'Func' or\r\n" +" 'Seg' parameters are not, Function or Seg are set to the default value of 0.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display all PCI devices in the system:\r\n" +" Shell> pci\r\n" +" \r\n" +" * To display the configuration space of Bus 0, Device 0, Function 0:\r\n" +" Shell> pci 00 00 00 -i\r\n" +" \r\n" +" * To display configuration space of Segment 0, Bus 0, Device 0, Function 0:\r\n" +" Shell> pci 00 00 00 -s 0\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS Data was displayed as requested.\r\n" +" SHELL_DEVICE_ERROR The specified device parameters did not match a physical\r\n" +" device in the system.\r\n" + +#string STR_GET_HELP_SMBIOSVIEW #language en-US "" +".TH smbiosview 0 "Displays SMBIOS information."\r\n" +".SH NAME\r\n" +"Displays SMBIOS information.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"SMBIOSVIEW [-t SmbiosType]|[-h SmbiosHandle]|[-s]|[-a]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -t - Displays all structures of SmbiosType.\r\n" +" -h - Displays structure of SmbiosHandle.\r\n" +" -s - Displays a statistics table.\r\n" +" -a - Displays all information.\r\n" +" SmbiosType - Specifies a SMBIOS structure type.\r\n" +" SmbiosHandle - Specifies a SMBIOS structure unique 16-bit handle.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. The SmbiosType parameter supports the following types:\n" +" 0 - BIOS Information\r\n" +" 1 - System Information\r\n" +" 2 - Baseboard Information\r\n" +" 3 - System Enclosure\r\n" +" 4 - Processor Information\r\n" +" 5 - Memory Controller Information\r\n" +" 6 - Memory Module Information\r\n" +" 7 - Cache Information\r\n" +" 8 - Port Connector Information\r\n" +" 9 - System Slots\r\n" +" 10 - On Board Devices Information\r\n" +" 11 - OEM Strings\r\n" +" 12 - System Configuration Options\r\n" +" 13 - BIOS Language Information\r\n" +" 14 - Group Associations\r\n" +" 15 - System Event Log\r\n" +" 16 - Physical Memory Array\r\n" +" 17 - Memory Device\r\n" +" 18 - 32-bit Memory Error Information\r\n" +" 19 - Memory Array Mapped Address\r\n" +" 20 - Memory Device Mapped Address\r\n" +" 21 - Built-in Pointing Device\r\n" +" 22 - Portable Battery\r\n" +" 23 - System Reset\r\n" +" 24 - Hardware Security\r\n" +" 25 - System Power Controls\r\n" +" 26 - Voltage Probe\r\n" +" 27 - Cooling Device\r\n" +" 28 - Temperature Probe\r\n" +" 29 - Electrical Current Probe\r\n" +" 30 - Out-Of-Band Remote Access\r\n" +" 31 - Boot Integrity Services (BIS) Entry Point\r\n" +" 32 - System Boot Information\r\n" +" 33 - 64-Bit Memory Error Information\r\n" +" 34 - Management Device\r\n" +" 35 - Management Device Component\r\n" +" 36 - Management Device Threshold Data\r\n" +" 37 - Memory Channel\r\n" +" 38 - IPMI Device Information\r\n" +" 39 - System Power Supply\r\n" +" 40 - Additional Information\r\n" +" 41 - Onboard Devices Extended Information\r\n" +" 42 - Management Controller Host Interface\r\n" +" 43 - TPM Device\r\n" +" 44 - Processor Additional Information\r\n" +" 2. Enter the SmbiosHandle parameter in hexadecimal format.\r\n" +" Do not use the '0x' prefix format for hexadecimal values.\r\n" +" 3. Internal commands:\r\n" +" :q -------- quit smbiosview\r\n" +" :0 -------- Change smbiosview display NONE info\r\n" +" :1 -------- Change smbiosview display OUTLINE info\r\n" +" :2 -------- Change smbiosview display NORMAL info\r\n" +" :3 -------- Change smbiosview display DETAIL info\r\n" +" /? -------- Show help\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS Data was displayed as requested.\r\n" +" SHELL_DEVICE_ERROR The requested structure was not found.\r\n" + +#string STR_GET_HELP_DMPSTORE #language en-US "" +".TH dmpstore 0 "Manages all UEFI variables."\r\n" +".SH NAME\r\n" +"Manages all UEFI variables.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"DMPSTORE [-b] [-d] [-all | ([variable] [-guid guid])] [-sfo]\r\n" +"DMPSTORE [-all | ([variable] [-guid guid])] [-s file]\r\n" +"DMPSTORE [-all | ([variable] [-guid guid])] [-l file]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -b - Displays one screen at a time.\r\n" +" -guid - Specifies the GUID of the variables to be displayed in\r\n" +" standard text format. If not specified and -all is not\r\n" +" specified, the EFI_GLOBAL_VARIABLE GUID is assumed.\r\n" +" -sfo - Displays information as described in Standard-Format Output.\r\n" +" -all - Dumps all variables, including those\r\n" +" with a different GUID than EFI_GLOBAL_VARIABLE.\r\n" +" -d - Delete variables.\r\n" +" -s - Saves variables to a file.\r\n" +" -l - Loads and sets variables from a file.\r\n" +" variable - Specifies a variable name. This can be a literal name or\r\n" +" a pattern as specified in the MetaiMatch() function of the\r\n" +" EFI_UNICODE_COLLATION2_PROCOOL.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command manages the UEFI variables. The variables\r\n" +" displayed or deleted depend on the command line options, as specified in\r\n" +" the following table:\r\n" +" Variable GUID -all Description\r\n" +" --- --- --- All variables with the GUID EFI_GLOBAL_VARIABLE will\r\n" +" be operated on.\r\n" +" --- --- X All variables (regardless of GUID or name) will be\r\n" +" operated on.\r\n" +" --- X --- All variables with the specified GUID will be\r\n" +" operated on.\r\n" +" X --- --- The variable with the GUID EFI_GLOBAL_VARIABLE and\r\n" +" the name Variable will be operated on.\r\n" +" X X --- The variable with the specified GUID and name\r\n" +" Variable will be operated on.\r\n" +" 2. The variable value is printed as a hexadecimal dump.\r\n" +" 3. Option -d is used to delete variables. Option -s and -l are used to save\r\n" +" and load variables to and from a file. The variable name can be specified\r\n" +" when using these flags so that the operation only takes effect on\r\n" +" that variable.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To dump all variables with the GUID EFI_GLOBAL_VARIABLE:\r\n" +" Shell> dmpstore\r\n" +" \r\n" +" * To dump all variables (regardless of GUID or name):\r\n" +" Shell> dmpstore -all\r\n" +" \r\n" +" * To dump the 'path' variable with the GUID '158DEF5A-F656-419C-B027-\r\n" +" 7A3192C079D2':\r\n" +" Shell> dmpstore path -guid 158DEF5A-F656-419C-B027-7A3192C079D2\r\n" +" \r\n" +" * To save all variables (regardless of GUID or name) to a file 'VarDump.txt':\r\n" +" fs0:\> dmpstore -all -s VarDump.txt\r\n" +" \r\n" +" * To delete the 'BootOrder' variable with the GUID EFI_GLOBAL_VARIABLE:\r\n" +" Shell> dmpstore -d BootOrder\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_INVALID_PARAMETER One of the passed-in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" + +#string STR_GET_HELP_DBLK #language en-US "" +".TH dblk 0 "Displays one or more blocks from a block device."\r\n" +".SH NAME\r\n" +"Displays one or more blocks from a block device.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"DBLK device [lba] [blocks] [-b]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -b - Displays one screen at a time.\r\n" +" device - Blocks the device name.\r\n" +" lba - Specifies the index of the first block to be displayed (a hexadecimal number).\r\n" +" The default is 0.\r\n" +" blocks - Specifies the number of blocks to display (a hexadecimal number). The default\r\n" +" is 1. If larger than 0x10, then only 0x10 are displayed.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command displays the contents of one or more blocks from a block\r\n" +" device. Enter a hexidecimal value for the lba and blocks variables. If lba is not\r\n" +" specified, block #0 is assumed. If blocks is not specified, on1y one\r\n" +" block is displayed. The maximum number of blocks that can be\r\n" +" displayed at one time is 0x10.\r\n" +" 2. If an MBR is found on the block, the partition information is displayed\r\n" +" after all the block contents are displayed.\r\n" +" 3. If the block is a FAT partition, some FAT parameters are displayed\r\n" +" (label, systemid, oemid, sectorsize, clustersize, media, and so forth) after all the\r\n" +" blocks are displayed.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display one block of blk0, beginning from block 0:\r\n" +" Shell> dblk blk0\r\n" +" \r\n" +" * To display one block of fs0, beginning from block 0x2:\r\n" +" Shell> dblk fs0 2\r\n" +" \r\n" +" * To display 0x5 blocks of fs0, beginning from block 0x12:\r\n" +" Shell> dblk fs0 12 5\r\n" +" \r\n" +" * To display 0x10 blocks of fs0, beginning from block 0x12:\r\n" +" Shell> dblk fs0 12 10\r\n" +" \r\n" +" * To attempt to display more than 0x10 blocks, resulting in only 0x10\r\n" +" blocks being displayed:\r\n" +" Shell> dblk fs0 12 20\r\n" +" \r\n" +" * To display one block of blk2, beginning from the first block (blk0):\r\n" +" fs1:\tmps1> dblk blk2 0 1\r\n" +" \r\n" + +#string STR_GET_HELP_EDIT #language en-US "" +".TH edit 0 "Provides a full screen text editor for ASCII or UCS-2 files."\r\n" +".SH NAME\r\n" +"Provides a full screen text editor for ASCII or UCS-2 files.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"EDIT [file]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" file - Specifies the name of file to be edited. If none is specified, an empty file\r\n" +" is created with a default file name.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command enables full screen file editing.\r\n" +" 2. The editor supports both UCS-2 and ASCII file types.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To edit the 'shell.log' file:\r\n" +" fs0:\> edit shell.log\r\n" + +#string STR_GET_HELP_HEXEDIT #language en-US "" +".TH hexedit 0 "Provides a full screen hex editor for files, block devices, or memory."\r\n" +".SH NAME\r\n" +"Provides a full screen hex editor for files, block devices, or memory.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"HEXEDIT [[-f] filename| [-d diskname offset size] | [-m address size]]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -f - Specifies the name of the file to edit.\r\n" +" -d - Specifies the disk block to edit:\r\n" +" DiskName - Name of the disk to edit (for example fs0)\r\n" +" Offset - Starting block number (beginning from 0)\r\n" +" Size - Number of blocks to edit\r\n" +" -m - Specifies the memory region to edit:\r\n" +" Address - Starting 32-bit memory address (beginning from 0)\r\n" +" Size - Size of memory region to edit in bytes\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command enables you to edit a file, block device, or memory region.\r\n" +" 2. The region being edited is displayed as hexadecimal bytes. The\r\n" +" contents can be modified and saved.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To edit a file in hex mode:\r\n" +" fs0:\> hexedit test.bin\r\n" +" \r\n" +" * To edit block device fs0 starting at block 0 with size of 2 blocks:\r\n" +" fs0:\> hexedit -d fs0 0 2\r\n" +" \r\n" +" * To edit memory region starting at address 0x00000000 with size of 2 bytes:\r\n" +" fs0:\> hexedit -m 0 2\r\n" + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Connect.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Connect.c new file mode 100644 index 00000000..359446fc --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Connect.c @@ -0,0 +1,543 @@ +/** @file + Main file for connect shell Driver1 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDriver1CommandsLib.h" + +/** + Create all handles associate with every device path node. + + @param DevicePathToConnect The device path which will be connected. + + @retval EFI_SUCCESS All handles associate with every device path node + have been created. + @retval EFI_INVALID_PARAMETER DevicePathToConnect is NULL. + @retval EFI_NOT_FOUND Create the handle associate with one device path + node failed + +**/ +EFI_STATUS +ShellConnectDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathToConnect + ) +{ + EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath; + EFI_STATUS Status; + EFI_HANDLE Handle; + EFI_HANDLE PreviousHandle; + + if (DevicePathToConnect == NULL) { + return EFI_INVALID_PARAMETER; + } + + PreviousHandle = NULL; + do{ + RemainingDevicePath = DevicePathToConnect; + Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &Handle); + + if (!EFI_ERROR (Status) && (Handle != NULL)) { + if (PreviousHandle == Handle) { + Status = EFI_NOT_FOUND; + } else { + PreviousHandle = Handle; + Status = gBS->ConnectController (Handle, NULL, RemainingDevicePath, FALSE); + } + } + + } while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath) ); + + return Status; + +} + +/** + Connect drivers for PCI root bridge. + + @retval EFI_SUCCESS Connect drivers successfully. + @retval EFI_NOT_FOUND Cannot find PCI root bridge device. + +**/ +EFI_STATUS +ShellConnectPciRootBridge ( + VOID + ) +{ + UINTN RootBridgeHandleCount; + EFI_HANDLE *RootBridgeHandleBuffer; + UINTN RootBridgeIndex; + EFI_STATUS Status; + + RootBridgeHandleCount = 0; + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiPciRootBridgeIoProtocolGuid, + NULL, + &RootBridgeHandleCount, + &RootBridgeHandleBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + for (RootBridgeIndex = 0; RootBridgeIndex < RootBridgeHandleCount; RootBridgeIndex++) { + gBS->ConnectController (RootBridgeHandleBuffer[RootBridgeIndex], NULL, NULL, FALSE); + } + + FreePool (RootBridgeHandleBuffer); + + return EFI_SUCCESS; +} + + +/** + Connect controller(s) and driver(s). + + @param[in] ControllerHandle The handle to the controller. Should have driver binding on it. + @param[in] DriverHandle The handle to the driver. Should have driver binding. + @param[in] Recursive TRUE to connect recursively, FALSE otherwise. + @param[in] Output TRUE to have info on the screen, FALSE otherwise. + @param[in] AlwaysOutput Override Output for errors. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ConnectControllers ( + IN CONST EFI_HANDLE ControllerHandle OPTIONAL, + IN CONST EFI_HANDLE DriverHandle OPTIONAL, + IN CONST BOOLEAN Recursive, + IN CONST BOOLEAN Output, + IN CONST BOOLEAN AlwaysOutput + ) +{ + EFI_STATUS Status; + EFI_STATUS Status2; + EFI_HANDLE *ControllerHandleList; + EFI_HANDLE *DriverHandleList; + EFI_HANDLE *HandleWalker; + + ControllerHandleList = NULL; + Status = EFI_NOT_FOUND; + Status2 = EFI_NOT_FOUND; + + // + // If we have a single handle to connect make that a 'list' + // + if (DriverHandle == NULL) { + DriverHandleList = NULL; + } else { + DriverHandleList = AllocateZeroPool(2*sizeof(EFI_HANDLE)); + if (DriverHandleList == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + DriverHandleList[0] = DriverHandle; + DriverHandleList[1] = NULL; + } + + // + // do we connect all controllers (with a loop) or a single one... + // This is where we call the gBS->ConnectController function. + // + if (ControllerHandle == NULL) { + ControllerHandleList = GetHandleListByProtocol(&gEfiDevicePathProtocolGuid); + for (HandleWalker = ControllerHandleList + ; HandleWalker != NULL && *HandleWalker != NULL + ; HandleWalker++ + ){ + Status = gBS->ConnectController(*HandleWalker, DriverHandleList, NULL, Recursive); + if (!EFI_ERROR(Status)) { + Status2 = EFI_SUCCESS; + } + if ((Output && !EFI_ERROR(Status)) || AlwaysOutput) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_HANDLE_RESULT), gShellDriver1HiiHandle, L"Connect", ConvertHandleToHandleIndex(*HandleWalker), Status); + } + } + } else { + Status = gBS->ConnectController(ControllerHandle, DriverHandleList, NULL, Recursive); + if (!EFI_ERROR(Status)) { + Status2 = EFI_SUCCESS; + } + if ((Output && !EFI_ERROR(Status)) || AlwaysOutput) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_HANDLE_RESULT), gShellDriver1HiiHandle, L"Connect", ConvertHandleToHandleIndex(ControllerHandle), Status); + } + } + + // + // Free any memory we allocated. + // + if (ControllerHandleList != NULL) { + FreePool(ControllerHandleList); + } + if (DriverHandleList != NULL) { + FreePool(DriverHandleList); + } + return (Status2); +} + +/** + Do a connect from an EFI variable via it's key name. + + @param[in] Key The name of the EFI Variable. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ShellConnectFromDevPaths ( + IN CONST CHAR16 *Key + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevPath; + EFI_DEVICE_PATH_PROTOCOL *CopyOfDevPath; + EFI_DEVICE_PATH_PROTOCOL *Instance; + EFI_DEVICE_PATH_PROTOCOL *Next; + UINTN Length; + UINTN Index; + UINTN HandleArrayCount; + UINTN Size; + EFI_HANDLE *HandleArray; + EFI_STATUS Status; + BOOLEAN AtLeastOneConnected; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT8 Class[3]; + + DevPath = NULL; + Length = 0; + AtLeastOneConnected = FALSE; + + // + // Get the DevicePath buffer from the variable... + // + Status = gRT->GetVariable((CHAR16*)Key, (EFI_GUID*)&gEfiGlobalVariableGuid, NULL, &Length, DevPath); + if (Status == EFI_BUFFER_TOO_SMALL) { + DevPath = AllocateZeroPool(Length); + if (DevPath == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Status = gRT->GetVariable((CHAR16*)Key, (EFI_GUID*)&gEfiGlobalVariableGuid, NULL, &Length, DevPath); + if (EFI_ERROR (Status)) { + if (DevPath != NULL) { + FreePool (DevPath); + } + return Status; + } + } else if (EFI_ERROR (Status)) { + return Status; + } + + Status = EFI_NOT_FOUND; + + CopyOfDevPath = DevPath; + // + // walk the list of devices and connect them + // + do { + // + // Check every instance of the console variable + // + Instance = GetNextDevicePathInstance (&CopyOfDevPath, &Size); + if (Instance == NULL) { + if (DevPath != NULL) { + FreePool (DevPath); + } + return EFI_UNSUPPORTED; + } + + Next = Instance; + while (!IsDevicePathEndType (Next)) { + Next = NextDevicePathNode (Next); + } + + SetDevicePathEndNode (Next); + // + // connect short form device path + // + if ((DevicePathType (Instance) == MESSAGING_DEVICE_PATH) && + ((DevicePathSubType (Instance) == MSG_USB_CLASS_DP) + || (DevicePathSubType (Instance) == MSG_USB_WWID_DP) + )) { + + Status = ShellConnectPciRootBridge (); + if (EFI_ERROR(Status)) { + FreePool(Instance); + FreePool(DevPath); + return Status; + } + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiPciIoProtocolGuid, + NULL, + &HandleArrayCount, + &HandleArray + ); + + if (!EFI_ERROR (Status)) { + for (Index = 0; Index < HandleArrayCount; Index++) { + Status = gBS->HandleProtocol ( + HandleArray[Index], + &gEfiPciIoProtocolGuid, + (VOID **)&PciIo + ); + + if (!EFI_ERROR (Status)) { + Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x09, 3, &Class); + if (!EFI_ERROR (Status)) { + if ((PCI_CLASS_SERIAL == Class[2]) && + (PCI_CLASS_SERIAL_USB == Class[1])) { + Status = gBS->ConnectController ( + HandleArray[Index], + NULL, + Instance, + FALSE + ); + if (!EFI_ERROR(Status)) { + AtLeastOneConnected = TRUE; + } + } + } + } + } + } + + if (HandleArray != NULL) { + FreePool (HandleArray); + } + } else { + // + // connect the entire device path + // + Status = ShellConnectDevicePath (Instance); + if (!EFI_ERROR (Status)) { + AtLeastOneConnected = TRUE; + } + } + FreePool (Instance); + + } while (CopyOfDevPath != NULL); + + if (DevPath != NULL) { + FreePool(DevPath); + } + + if (AtLeastOneConnected) { + return EFI_SUCCESS; + } else { + return EFI_NOT_FOUND; + } + +} + +/** + Convert the handle identifiers from strings and then connect them. + + One of them should have driver binding and either can be NULL. + + @param[in] Handle1 The first handle. + @param[in] Handle2 The second handle. + @param[in] Recursive TRUE to do connect recursively. FALSE otherwise. + @param[in] Output TRUE to have output to screen. FALSE otherwise. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ConvertAndConnectControllers ( + IN EFI_HANDLE Handle1 OPTIONAL, + IN EFI_HANDLE Handle2 OPTIONAL, + IN CONST BOOLEAN Recursive, + IN CONST BOOLEAN Output + ) +{ + // + // if only one is NULL verify it's the proper one... + // + if ( (Handle1 == NULL && Handle2 != NULL) + || (Handle1 != NULL && Handle2 == NULL) + ){ + // + // Figure out which one should be NULL and move the handle to the right place. + // If Handle1 is NULL then test Handle2 and vise versa. + // The one that DOES has driver binding must be Handle2 + // + if (Handle1 == NULL) { + if (EFI_ERROR(gBS->OpenProtocol(Handle2, &gEfiDriverBindingProtocolGuid, NULL, NULL, gImageHandle, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) { + // swap + Handle1 = Handle2; + Handle2 = NULL; + } else { + // We're all good... + } + } else { + if (EFI_ERROR(gBS->OpenProtocol(Handle1, &gEfiDriverBindingProtocolGuid, NULL, NULL, gImageHandle, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) { + // We're all good... + } else { + // swap + Handle2 = Handle1; + Handle1 = NULL; + } + } + } + + return (ConnectControllers(Handle1, Handle2, Recursive, Output, (BOOLEAN)(Handle2 != NULL && Handle1 != NULL))); +} + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-c", TypeFlag}, + {L"-r", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'connect' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunConnect ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CONST CHAR16 *Param1; + CONST CHAR16 *Param2; + UINTN Count; + EFI_HANDLE Handle1; + EFI_HANDLE Handle2; + UINT64 Intermediate; + + ShellStatus = SHELL_SUCCESS; + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDriver1HiiHandle, L"connect", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // if more than 2 'value' parameters (plus the name one) or either -r or -c with any value parameters we have too many parameters + // + Count = (gInReconnect?0x4:0x3); + if ((ShellCommandLineGetCount(Package) > Count) + ||(ShellCommandLineGetFlag(Package, L"-c") && ShellCommandLineGetCount(Package)>1) + ||(ShellCommandLineGetFlag(Package, L"-r") && ShellCommandLineGetCount(Package)>2) + ||(ShellCommandLineGetFlag(Package, L"-r") && ShellCommandLineGetFlag(Package, L"-c") ) + ){ + // + // error for too many parameters + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDriver1HiiHandle, L"connect"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetFlag(Package, L"-c")) { + // + // do the conin and conout from EFI variables + // if the first fails dont 'loose' the error + // + Status = ShellConnectFromDevPaths(L"ConInDev"); + if (EFI_ERROR(Status)) { + ShellConnectFromDevPaths(L"ConOutDev"); + } else { + Status = ShellConnectFromDevPaths(L"ConOutDev"); + } + if (EFI_ERROR(Status)) { + ShellConnectFromDevPaths(L"ErrOutDev"); + } else { + Status = ShellConnectFromDevPaths(L"ErrOutDev"); + } + if (EFI_ERROR(Status)) { + ShellConnectFromDevPaths(L"ErrOut"); + } else { + Status = ShellConnectFromDevPaths(L"ErrOut"); + } + if (EFI_ERROR(Status)) { + ShellConnectFromDevPaths(L"ConIn"); + } else { + Status = ShellConnectFromDevPaths(L"ConIn"); + } + if (EFI_ERROR(Status)) { + ShellConnectFromDevPaths(L"ConOut"); + } else { + Status = ShellConnectFromDevPaths(L"ConOut"); + } + if (EFI_ERROR(Status)) { + ShellStatus = SHELL_DEVICE_ERROR; + } + } else { + // + // 0, 1, or 2 specific handles and possibly recursive + // + Param1 = ShellCommandLineGetRawValue(Package, 1); + Param2 = ShellCommandLineGetRawValue(Package, 2); + Count = ShellCommandLineGetCount(Package); + + if (Param1 != NULL) { + Status = ShellConvertStringToUint64(Param1, &Intermediate, TRUE, FALSE); + Handle1 = ConvertHandleIndexToHandle((UINTN)Intermediate); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"connect", Param1); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } else { + Handle1 = NULL; + } + + if (Param2 != NULL) { + Status = ShellConvertStringToUint64(Param2, &Intermediate, TRUE, FALSE); + Handle2 = ConvertHandleIndexToHandle((UINTN)Intermediate); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"connect", Param2); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } else { + Handle2 = NULL; + } + + if (ShellStatus == SHELL_SUCCESS) { + if (Param1 != NULL && Handle1 == NULL){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"connect", Param1); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (Param2 != NULL && Handle2 == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"connect", Param2); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (Handle2 != NULL && Handle1 != NULL && EFI_ERROR(gBS->OpenProtocol(Handle2, &gEfiDriverBindingProtocolGuid, NULL, gImageHandle, NULL, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"connect", Param2); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = ConvertAndConnectControllers(Handle1, Handle2, ShellCommandLineGetFlag(Package, L"-r"), (BOOLEAN)(Count!=0)); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CONNECT_NONE), gShellDriver1HiiHandle); + ShellStatus = SHELL_DEVICE_ERROR; + } + } + } + } + + ShellCommandLineFreeVarList (Package); + } + return (ShellStatus); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/DevTree.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/DevTree.c new file mode 100644 index 00000000..82321a4d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/DevTree.c @@ -0,0 +1,271 @@ +/** @file + Main file for DevTree shell Driver1 function. + + (C) Copyright 2014-2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDriver1CommandsLib.h" + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-d", TypeFlag}, + {L"-l", TypeValue}, + {NULL, TypeMax} + }; + +/** + Display a tree starting from this handle. + + @param[in] TheHandle The handle to start with. + @param[in] Lang Optionally, a UEFI defined language code. + @param[in] UseDevPaths TRUE to display info from DevPath as identifiers. + FALSE will use component name protocol instead. + @param[in] IndentCharCount How many characters to indent (allows for recursion). + @param[in] HiiString The string from HII to use for output. + + @retval SHELL_SUCCESS The operation was successful. +**/ +SHELL_STATUS +DoDevTreeForHandle( + IN CONST EFI_HANDLE TheHandle, + IN CONST CHAR8 *Lang OPTIONAL, + IN CONST BOOLEAN UseDevPaths, + IN CONST UINTN IndentCharCount, + IN CONST CHAR16 *HiiString + ) +{ + SHELL_STATUS ShellStatus; + EFI_STATUS Status; + CHAR16 *FormatString; + CHAR16 *Name; + EFI_HANDLE *ChildHandleBuffer; + UINTN ChildCount; + UINTN LoopVar; + + Status = EFI_SUCCESS; + ShellStatus = SHELL_SUCCESS; + Name = NULL; + ChildHandleBuffer = NULL; + ChildCount = 0; + + ASSERT (TheHandle != NULL); + ASSERT (HiiString != NULL); + + if (ShellGetExecutionBreakFlag()) { + ShellStatus = SHELL_ABORTED; + return ShellStatus; + } + + // + // We want controller handles. they will not have LoadedImage or DriverBinding (or others...) + // + Status = gBS->OpenProtocol ( + TheHandle, + &gEfiDriverBindingProtocolGuid, + NULL, + NULL, + NULL, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + return SHELL_SUCCESS; + } + + Status = gBS->OpenProtocol ( + TheHandle, + &gEfiLoadedImageProtocolGuid, + NULL, + NULL, + NULL, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + return SHELL_SUCCESS; + } + + FormatString = AllocateZeroPool(StrSize(HiiString) + (10)*sizeof(FormatString[0])); + if (FormatString == NULL) { + return SHELL_OUT_OF_RESOURCES; + } + + // + // we generate the format string on the fly so that we can control the + // number of space characters that the first (empty) string has. this + // handles the indenting. + // + + UnicodeSPrint(FormatString, StrSize(HiiString) + (10)*sizeof(FormatString[0]), L"%%%ds %s", IndentCharCount, HiiString); + gEfiShellProtocol->GetDeviceName((EFI_HANDLE)TheHandle, !UseDevPaths?EFI_DEVICE_NAME_USE_COMPONENT_NAME|EFI_DEVICE_NAME_USE_DEVICE_PATH:EFI_DEVICE_NAME_USE_DEVICE_PATH, (CHAR8*)Lang, &Name); + // + // print out the information for ourselves + // + ShellPrintEx( + -1, + -1, + FormatString, + L"", + ConvertHandleToHandleIndex(TheHandle), + Name==NULL?L"Unknown":Name); + + FreePool(FormatString); + if (Name != NULL) { + FreePool(Name); + } + + // + // recurse on each child handle with IndentCharCount + 2 + // + ParseHandleDatabaseForChildControllers(TheHandle, &ChildCount, &ChildHandleBuffer); + for (LoopVar = 0 ; LoopVar < ChildCount && ShellStatus == SHELL_SUCCESS; LoopVar++){ + ShellStatus = DoDevTreeForHandle(ChildHandleBuffer[LoopVar], Lang, UseDevPaths, IndentCharCount+2, HiiString); + if (ShellStatus == SHELL_ABORTED) { + break; + } + } + + if (ChildHandleBuffer != NULL) { + FreePool(ChildHandleBuffer); + } + + return (ShellStatus); +} + +/** + Function for 'devtree' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunDevTree ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CHAR8 *Language; + CONST CHAR16 *Lang; + CHAR16 *HiiString; + UINTN LoopVar; + EFI_HANDLE TheHandle; + BOOLEAN FlagD; + UINT64 Intermediate; + UINTN ParentControllerHandleCount; + EFI_HANDLE *ParentControllerHandleBuffer; + + ShellStatus = SHELL_SUCCESS; + Status = EFI_SUCCESS; + Language = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDriver1HiiHandle, L"devtree", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetCount(Package) > 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDriver1HiiHandle, L"devtree"); + ShellCommandLineFreeVarList (Package); + return (SHELL_INVALID_PARAMETER); + } + Lang = ShellCommandLineGetValue(Package, L"-l"); + if (Lang != NULL) { + Language = AllocateZeroPool(StrSize(Lang)); + AsciiSPrint(Language, StrSize(Lang), "%S", Lang); + } else if (!ShellCommandLineGetFlag(Package, L"-l")){ + ASSERT(Language == NULL); +// Language = AllocateZeroPool(10); +// AsciiSPrint(Language, 10, "en-us"); + } else { + ASSERT(Language == NULL); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDriver1HiiHandle, L"devtree", L"-l"); + ShellCommandLineFreeVarList (Package); + return (SHELL_INVALID_PARAMETER); + } + FlagD = ShellCommandLineGetFlag(Package, L"-d"); + + Lang = ShellCommandLineGetRawValue(Package, 1); + HiiString = HiiGetString(gShellDriver1HiiHandle, STRING_TOKEN (STR_DEV_TREE_OUTPUT), Language); + + if (Lang == NULL) { + for (LoopVar = 1 ; ; LoopVar++){ + TheHandle = ConvertHandleIndexToHandle(LoopVar); + if (TheHandle == NULL){ + break; + } + + // + // Skip handles that do not have device path protocol + // + Status = gBS->OpenProtocol ( + TheHandle, + &gEfiDevicePathProtocolGuid, + NULL, + NULL, + NULL, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (EFI_ERROR (Status)) { + continue; + } + + // + // Skip handles that do have parents + // + ParentControllerHandleBuffer = NULL; + Status = PARSE_HANDLE_DATABASE_PARENTS ( + TheHandle, + &ParentControllerHandleCount, + &ParentControllerHandleBuffer + ); + SHELL_FREE_NON_NULL (ParentControllerHandleBuffer); + if (ParentControllerHandleCount > 0) { + continue; + } + + // + // Start a devtree from TheHandle that has a device path and no parents + // + ShellStatus = DoDevTreeForHandle(TheHandle, Language, FlagD, 0, HiiString); + } + } else { + Status = ShellConvertStringToUint64(Lang, &Intermediate, TRUE, FALSE); + if (EFI_ERROR(Status) || ConvertHandleIndexToHandle((UINTN)Intermediate) == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"devtree", Lang); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ShellStatus = DoDevTreeForHandle(ConvertHandleIndexToHandle((UINTN)Intermediate), Language, FlagD, 0, HiiString); + } + } + + if (HiiString != NULL) { + FreePool(HiiString); + } + SHELL_FREE_NON_NULL(Language); + ShellCommandLineFreeVarList (Package); + } + + return (ShellStatus); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Devices.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Devices.c new file mode 100644 index 00000000..2851c3d6 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Devices.c @@ -0,0 +1,263 @@ +/** @file + Main file for devices shell Driver1 function. + + (C) Copyright 2012-2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDriver1CommandsLib.h" + +/** + Get lots of info about a device from its handle. + + @param[in] TheHandle The device handle to get info on. + @param[in, out] Type On successful return R, B, or D (root, bus, or + device) will be placed in this buffer. + @param[in, out] Cfg On successful return this buffer will be + TRUE if the handle has configuration, FALSE + otherwise. + @param[in, out] Diag On successful return this buffer will be + TRUE if the handle has disgnostics, FALSE + otherwise. + @param[in, out] Parents On successful return this buffer will be + contain the number of parent handles. + @param[in, out] Devices On successful return this buffer will be + contain the number of devices controlled. + @param[in, out] Children On successful return this buffer will be + contain the number of child handles. + @param[out] Name The pointer to a buffer that will be allocated + and contain the string name of the handle. + The caller must free this memory. + @param[in] Language The language code as defined by the UEFI spec. + + @retval EFI_SUCCESS The info is there. + @retval EFI_INVALID_PARAMETER A parameter was invalid. +**/ +EFI_STATUS +GetDeviceHandleInfo ( + IN EFI_HANDLE TheHandle, + IN OUT CHAR16 *Type, + IN OUT BOOLEAN *Cfg, + IN OUT BOOLEAN *Diag, + IN OUT UINTN *Parents, + IN OUT UINTN *Devices, + IN OUT UINTN *Children, + OUT CHAR16 **Name, + IN CONST CHAR8 *Language + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN Count; + + if (TheHandle == NULL + || Type == NULL + || Cfg == NULL + || Diag == NULL + || Parents == NULL + || Devices == NULL + || Children == NULL + || Name == NULL ) { + return (EFI_INVALID_PARAMETER); + } + + *Cfg = FALSE; + *Diag = FALSE; + *Children = 0; + *Parents = 0; + *Devices = 0; + *Type = L' '; + *Name = CHAR_NULL; + HandleBuffer = NULL; + Status = EFI_SUCCESS; + + gEfiShellProtocol->GetDeviceName(TheHandle, EFI_DEVICE_NAME_USE_COMPONENT_NAME|EFI_DEVICE_NAME_USE_DEVICE_PATH, (CHAR8*)Language, Name); + + Status = ParseHandleDatabaseForChildControllers(TheHandle, Children, NULL); +// if (!EFI_ERROR(Status)) { + Status = PARSE_HANDLE_DATABASE_PARENTS(TheHandle, Parents, NULL); + if (/*!EFI_ERROR(Status) && */Parents != NULL && Children != NULL) { + if (*Parents == 0) { + *Type = L'R'; + } else if (*Children > 0) { + *Type = L'B'; + } else { + *Type = L'D'; + } + } +// } + Status = PARSE_HANDLE_DATABASE_UEFI_DRIVERS(TheHandle, Devices, &HandleBuffer); + if (!EFI_ERROR(Status) && Devices != NULL && HandleBuffer != NULL) { + for (Count = 0 ; Count < *Devices ; Count++) { + if (!EFI_ERROR(gBS->OpenProtocol(HandleBuffer[Count], &gEfiDriverConfigurationProtocolGuid, NULL, NULL, gImageHandle, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) { + *Cfg = TRUE; + } + if (!EFI_ERROR(gBS->OpenProtocol(HandleBuffer[Count], &gEfiDriverDiagnosticsProtocolGuid, NULL, NULL, gImageHandle, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) { + *Diag = TRUE; + } + if (!EFI_ERROR(gBS->OpenProtocol(HandleBuffer[Count], &gEfiDriverDiagnostics2ProtocolGuid, NULL, NULL, gImageHandle, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) { + *Diag = TRUE; + } + } + SHELL_FREE_NON_NULL(HandleBuffer); + } + + return (Status); +} + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-sfo", TypeFlag}, + {L"-l", TypeValue}, + {NULL, TypeMax} + }; + +/** + Function for 'devices' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunDevices ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CHAR8 *Language; + EFI_HANDLE *HandleList; + EFI_HANDLE *HandleListWalker; + CHAR16 Type; + BOOLEAN Cfg; + BOOLEAN Diag; + UINTN Parents; + UINTN Devices; + UINTN Children; + CHAR16 *Name; + CONST CHAR16 *Lang; + BOOLEAN SfoFlag; + + ShellStatus = SHELL_SUCCESS; + Language = NULL; + SfoFlag = FALSE; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDriver1HiiHandle, L"devices", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // if more than 0 'value' parameters we have too many parameters + // + if (ShellCommandLineGetRawValue(Package, 1) != NULL){ + // + // error for too many parameters + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDriver1HiiHandle, L"devices"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // get the language if necessary + // + Lang = ShellCommandLineGetValue(Package, L"-l"); + if (Lang != NULL) { + Language = AllocateZeroPool(StrSize(Lang)); + AsciiSPrint(Language, StrSize(Lang), "%S", Lang); + } else if (!ShellCommandLineGetFlag(Package, L"-l")){ + ASSERT(Language == NULL); +// Language = AllocateZeroPool(10); +// AsciiSPrint(Language, 10, "en-us"); + } else { + ASSERT(Language == NULL); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDriver1HiiHandle, L"devices", L"-l"); + ShellCommandLineFreeVarList (Package); + return (SHELL_INVALID_PARAMETER); + } + + + // + // Print Header + + // + if (ShellCommandLineGetFlag (Package, L"-sfo")) { + ShellPrintHiiEx (-1, -1, Language, STRING_TOKEN (STR_GEN_SFO_HEADER), gShellDriver1HiiHandle, L"devices"); + SfoFlag = TRUE; + } else { + ShellPrintHiiEx (-1, -1, Language, STRING_TOKEN (STR_DEVICES_HEADER_LINES), gShellDriver1HiiHandle); + } + + // + // loop through each handle + // + HandleList = GetHandleListByProtocol(NULL); + ASSERT(HandleList != NULL); + for (HandleListWalker = HandleList + ; HandleListWalker != NULL && *HandleListWalker != NULL /*&& !EFI_ERROR(Status)*/ + ; HandleListWalker++ + ){ + + // + // get all the info on each handle + // + Name = NULL; + Status = GetDeviceHandleInfo(*HandleListWalker, &Type, &Cfg, &Diag, &Parents, &Devices, &Children, &Name, Language); + if (Name != NULL && (Parents != 0 || Devices != 0 || Children != 0)) { + ShellPrintHiiEx ( + -1, + -1, + Language, + SfoFlag?STRING_TOKEN (STR_DEVICES_ITEM_LINE_SFO):STRING_TOKEN (STR_DEVICES_ITEM_LINE), + gShellDriver1HiiHandle, + ConvertHandleToHandleIndex (*HandleListWalker), + Type, + Cfg?(SfoFlag?L'Y':L'X'):(SfoFlag?L'N':L'-'), + Diag?(SfoFlag?L'Y':L'X'):(SfoFlag?L'N':L'-'), + Parents, + Devices, + Children, + Name!=NULL?Name:L""); + } + if (Name != NULL) { + FreePool(Name); + } + if (ShellGetExecutionBreakFlag ()) { + ShellStatus = SHELL_ABORTED; + break; + } + + } + + if (HandleList != NULL) { + FreePool(HandleList); + } + + } + SHELL_FREE_NON_NULL(Language); + ShellCommandLineFreeVarList (Package); + } + return (ShellStatus); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Dh.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Dh.c new file mode 100644 index 00000000..11b0f301 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Dh.c @@ -0,0 +1,1191 @@ +/** @file + Main file for Dh shell Driver1 function. + + (C) Copyright 2014-2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2017 Hewlett Packard Enterprise Development LP
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDriver1CommandsLib.h" + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-p", TypeValue}, + {L"-d", TypeFlag}, + {L"-v", TypeFlag}, + {L"-verbose", TypeFlag}, + {L"-sfo", TypeFlag}, + {L"-l", TypeValue}, + {NULL, TypeMax} + }; + +STATIC CONST EFI_GUID *UefiDriverModelProtocolsGuidArray[] = { + &gEfiDriverBindingProtocolGuid, + &gEfiPlatformDriverOverrideProtocolGuid, + &gEfiBusSpecificDriverOverrideProtocolGuid, + &gEfiDriverDiagnosticsProtocolGuid, + &gEfiDriverDiagnostics2ProtocolGuid, + &gEfiComponentNameProtocolGuid, + &gEfiComponentName2ProtocolGuid, + &gEfiPlatformToDriverConfigurationProtocolGuid, + &gEfiDriverSupportedEfiVersionProtocolGuid, + &gEfiDriverFamilyOverrideProtocolGuid, + &gEfiDriverHealthProtocolGuid, + &gEfiLoadedImageProtocolGuid, + NULL +}; + +UINTN mGuidDataLen[] = {8, 4, 4, 4, 12}; +/** + Function to determine if the string can convert to a GUID. + The string must be restricted as "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" format. + + @param[in] String The string to test. + + @retval TRUE The string can convert to a GUID. + @retval FALSE The string can't convert to a GUID. +**/ +BOOLEAN +IsValidGuidString( + IN CONST CHAR16 *String + ) +{ + CONST CHAR16 *Walker; + CONST CHAR16 *PrevWalker; + UINTN Index; + + if (String == NULL) { + return FALSE; + } + + Walker = String; + PrevWalker = String; + Index = 0; + + while (Walker != NULL && *Walker != CHAR_NULL) { + if ( (*Walker >= '0' && *Walker <= '9') || + (*Walker >= 'a' && *Walker <= 'f') || + (*Walker >= 'A' && *Walker <= 'F') + ) { + Walker++; + } else { + if (*Walker == L'-' && (((UINTN)Walker - (UINTN)PrevWalker) / sizeof (CHAR16)) == mGuidDataLen[Index]) { + Walker++; + PrevWalker = Walker; + Index++; + } else { + return FALSE; + } + } + } + + if ((((UINTN)Walker - (UINTN)PrevWalker) / sizeof (CHAR16)) == mGuidDataLen[Index]) { + return TRUE; + } else { + return FALSE; + } +} + +/** + Convert a hex-character to decimal value. + + This internal function only deal with Unicode character + which maps to a valid hexadecimal ASII character, i.e. + L'0' to L'9', L'a' to L'f' or L'A' to L'F'. For other + Unicode character, the value returned does not make sense. + + @param[in] Char The character to convert. + + @retval The numerical value converted. +**/ +UINTN +HexCharToDecimal( + IN CHAR16 Char + ) +{ + if (Char >= '0' && Char <= '9') { + return Char - L'0'; + } else if (Char >= 'a' && Char <= 'f') { + return Char - L'a' + 10; + } else { + return Char - L'A' + 10; + } +} + +/** + Function try to convert a string to GUID format. + + @param[in] String The string will be converted. + @param[out] Guid Save the result convert from string. + + @retval EFI_SUCCESS The string was successfully converted to a GUID. + @retval EFI_UNSUPPORTED The input string is not in registry format. +**/ +EFI_STATUS +ConvertStrToGuid( + IN CONST CHAR16 *String, + OUT GUID *Guid + ) +{ + CONST CHAR16 *Walker; + UINT8 TempValue; + UINTN Index; + + if (String == NULL || !IsValidGuidString (String)) { + return EFI_UNSUPPORTED; + } + + Index = 0; + + Walker = String; + Guid->Data1 = (UINT32)StrHexToUint64 (Walker); + + Walker += 9; + Guid->Data2 = (UINT16)StrHexToUint64 (Walker); + + Walker += 5; + Guid->Data3 = (UINT16)StrHexToUint64 (Walker); + + Walker += 5; + while (Walker != NULL && *Walker != CHAR_NULL) { + if (*Walker == L'-') { + Walker++; + } else { + TempValue = (UINT8)HexCharToDecimal (*Walker); + TempValue = (UINT8)LShiftU64 (TempValue, 4); + Walker++; + + TempValue += (UINT8)HexCharToDecimal (*Walker); + Walker++; + + Guid->Data4[Index] = TempValue; + Index++; + } + } + + return EFI_SUCCESS; +} + +/** + Get the name of a driver by it's handle. + + If a name is found the memory must be callee freed. + + @param[in] TheHandle The driver's handle. + @param[in] Language The language to use. + @param[in] NameFound Upon a successful return the name found. + + @retval EFI_SUCCESS The name was found. +**/ +EFI_STATUS +GetDriverName ( + IN EFI_HANDLE TheHandle, + IN CONST CHAR8 *Language, + IN CHAR16 **NameFound + ) +{ + CHAR8 *Lang; + EFI_STATUS Status; + EFI_COMPONENT_NAME2_PROTOCOL *CompName2; + CHAR16 *NameToReturn; + // + // Go through those handles until we get one that passes for GetComponentName + // + Status = gBS->OpenProtocol( + TheHandle, + &gEfiComponentName2ProtocolGuid, + (VOID**)&CompName2, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(Status)) { + Status = gBS->OpenProtocol( + TheHandle, + &gEfiComponentNameProtocolGuid, + (VOID**)&CompName2, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + } + + if (EFI_ERROR(Status)) { + return (EFI_NOT_FOUND); + } + Lang = GetBestLanguageForDriver (CompName2->SupportedLanguages, Language, FALSE); + Status = CompName2->GetDriverName(CompName2, Lang, &NameToReturn); + FreePool(Lang); + + if (!EFI_ERROR(Status) && NameToReturn != NULL) { + *NameFound = NULL; + StrnCatGrow(NameFound, NULL, NameToReturn, 0); + } + return (Status); +} + +/** + Discover if a protocol guid is one of the UEFI Driver Model Protocols. + + @param[in] Guid The guid to test. + + @retval TRUE The guid does represent a driver model protocol. + @retval FALSE The guid does not represent a driver model protocol. +**/ +BOOLEAN +IsDriverProt ( + IN CONST EFI_GUID *Guid + ) +{ + CONST EFI_GUID **GuidWalker; + BOOLEAN GuidFound; + GuidFound = FALSE; + for (GuidWalker = UefiDriverModelProtocolsGuidArray + ; GuidWalker != NULL && *GuidWalker != NULL + ; GuidWalker++ + ){ + if (CompareGuid(*GuidWalker, Guid)) { + GuidFound = TRUE; + break; + } + } + return (GuidFound); +} + +/** + Get information for a handle. + + @param[in] TheHandle The handles to show info on. + @param[in] Language Language string per UEFI specification. + @param[in] Separator Separator string between information blocks. + @param[in] Verbose TRUE for extra info, FALSE otherwise. + @param[in] ExtraInfo TRUE for extra info, FALSE otherwise. + + @retval SHELL_SUCCESS The operation was successful. + @retval SHELL_INVALID_PARAMETER ProtocolName was NULL or invalid. +**/ +CHAR16* +GetProtocolInfoString( + IN CONST EFI_HANDLE TheHandle, + IN CONST CHAR8 *Language, + IN CONST CHAR16 *Separator, + IN CONST BOOLEAN Verbose, + IN CONST BOOLEAN ExtraInfo + ) +{ + EFI_GUID **ProtocolGuidArray; + UINTN ArrayCount; + UINTN ProtocolIndex; + EFI_STATUS Status; + CHAR16 *RetVal; + UINTN Size; + CHAR16 *Temp; + CHAR16 GuidStr[40]; + VOID *Instance; + CHAR16 InstanceStr[17]; + + ProtocolGuidArray = NULL; + RetVal = NULL; + Size = 0; + + Status = gBS->ProtocolsPerHandle ( + TheHandle, + &ProtocolGuidArray, + &ArrayCount + ); + if (!EFI_ERROR (Status)) { + for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) { + Temp = GetStringNameFromGuid(ProtocolGuidArray[ProtocolIndex], Language); + ASSERT((RetVal == NULL && Size == 0) || (RetVal != NULL)); + if (Size != 0) { + StrnCatGrow(&RetVal, &Size, Separator, 0); + } + StrnCatGrow(&RetVal, &Size, L"%H", 0); + if (Temp == NULL) { + UnicodeSPrint (GuidStr, sizeof (GuidStr), L"%g", ProtocolGuidArray[ProtocolIndex]); + StrnCatGrow (&RetVal, &Size, GuidStr, 0); + } else { + StrnCatGrow(&RetVal, &Size, Temp, 0); + FreePool(Temp); + } + StrnCatGrow(&RetVal, &Size, L"%N", 0); + + if(Verbose) { + Status = gBS->HandleProtocol (TheHandle, ProtocolGuidArray[ProtocolIndex], &Instance); + if (!EFI_ERROR (Status)) { + StrnCatGrow (&RetVal, &Size, L"(%H", 0); + UnicodeSPrint (InstanceStr, sizeof (InstanceStr), L"%x", Instance); + StrnCatGrow (&RetVal, &Size, InstanceStr, 0); + StrnCatGrow (&RetVal, &Size, L"%N)", 0); + } + } + + if (ExtraInfo) { + Temp = GetProtocolInformationDump(TheHandle, ProtocolGuidArray[ProtocolIndex], Verbose); + if (Temp != NULL) { + ASSERT((RetVal == NULL && Size == 0) || (RetVal != NULL)); + if (!Verbose) { + StrnCatGrow(&RetVal, &Size, L"(", 0); + StrnCatGrow(&RetVal, &Size, Temp, 0); + StrnCatGrow(&RetVal, &Size, L")", 0); + } else { + StrnCatGrow(&RetVal, &Size, Separator, 0); + StrnCatGrow(&RetVal, &Size, Temp, 0); + } + FreePool(Temp); + } + } + } + } + + SHELL_FREE_NON_NULL(ProtocolGuidArray); + + if (RetVal == NULL) { + return (NULL); + } + + ASSERT((RetVal == NULL && Size == 0) || (RetVal != NULL)); + StrnCatGrow(&RetVal, &Size, Separator, 0); + return (RetVal); +} + +/** + Gets the name of the loaded image. + + @param[in] TheHandle The handle of the driver to get info on. + @param[out] Name The pointer to the pointer. Valid upon a successful return. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +GetDriverImageName ( + IN EFI_HANDLE TheHandle, + OUT CHAR16 **Name + ) +{ + // get loaded image and devicepathtotext on image->Filepath + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + if (TheHandle == NULL || Name == NULL) { + return (EFI_INVALID_PARAMETER); + } + + Status = gBS->OpenProtocol ( + TheHandle, + &gEfiLoadedImageProtocolGuid, + (VOID **) &LoadedImage, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR(Status)) { + return (Status); + } + DevicePath = LoadedImage->FilePath; + *Name = ConvertDevicePathToText(DevicePath, TRUE, TRUE); + return (EFI_SUCCESS); +} + +/** + Display driver model information for a given handle. + + @param[in] Handle The handle to display info on. + @param[in] BestName Use the best name? + @param[in] Language The language to output in. +**/ +EFI_STATUS +DisplayDriverModelHandle ( + IN EFI_HANDLE Handle, + IN BOOLEAN BestName, + IN CONST CHAR8 *Language OPTIONAL + ) +{ + EFI_STATUS Status; + BOOLEAN ConfigurationStatus; + BOOLEAN DiagnosticsStatus; + UINTN DriverBindingHandleCount; + EFI_HANDLE *DriverBindingHandleBuffer; + UINTN ParentControllerHandleCount; + EFI_HANDLE *ParentControllerHandleBuffer; + UINTN ChildControllerHandleCount; + EFI_HANDLE *ChildControllerHandleBuffer; + CHAR16 *TempStringPointer; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINTN Index; + CHAR16 *DriverName; + EFI_DRIVER_BINDING_PROTOCOL *DriverBinding; + UINTN NumberOfChildren; + UINTN HandleIndex; + UINTN ControllerHandleCount; + EFI_HANDLE *ControllerHandleBuffer; + UINTN ChildIndex; + BOOLEAN Image; + + DriverName = NULL; + + // + // See if Handle is a device handle and display its details. + // + DriverBindingHandleBuffer = NULL; + Status = PARSE_HANDLE_DATABASE_UEFI_DRIVERS ( + Handle, + &DriverBindingHandleCount, + &DriverBindingHandleBuffer + ); + + ParentControllerHandleBuffer = NULL; + Status = PARSE_HANDLE_DATABASE_PARENTS ( + Handle, + &ParentControllerHandleCount, + &ParentControllerHandleBuffer + ); + + ChildControllerHandleBuffer = NULL; + Status = ParseHandleDatabaseForChildControllers ( + Handle, + &ChildControllerHandleCount, + &ChildControllerHandleBuffer + ); + + DiagnosticsStatus = FALSE; + ConfigurationStatus = FALSE; + + if (!EFI_ERROR(gBS->OpenProtocol(Handle, &gEfiDriverConfigurationProtocolGuid, NULL, NULL, gImageHandle, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) { + ConfigurationStatus = TRUE; + } + if (!EFI_ERROR(gBS->OpenProtocol(Handle, &gEfiDriverConfiguration2ProtocolGuid, NULL, NULL, gImageHandle, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) { + ConfigurationStatus = TRUE; + } + if (!EFI_ERROR(gBS->OpenProtocol(Handle, &gEfiDriverDiagnosticsProtocolGuid, NULL, NULL, gImageHandle, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) { + DiagnosticsStatus = TRUE; + } + if (!EFI_ERROR(gBS->OpenProtocol(Handle, &gEfiDriverDiagnostics2ProtocolGuid, NULL, NULL, gImageHandle, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) { + DiagnosticsStatus = TRUE; + } + + Status = EFI_SUCCESS; + + if (DriverBindingHandleCount > 0 || ParentControllerHandleCount > 0 || ChildControllerHandleCount > 0) { + + + + DevicePath = NULL; + TempStringPointer = NULL; + Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID**)&DevicePath); + + Status = gEfiShellProtocol->GetDeviceName(Handle, EFI_DEVICE_NAME_USE_COMPONENT_NAME|EFI_DEVICE_NAME_USE_DEVICE_PATH, (CHAR8*)Language, &TempStringPointer); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_DH_OUTPUT_DRIVER1), gShellDriver1HiiHandle, TempStringPointer!=NULL?TempStringPointer:L""); + SHELL_FREE_NON_NULL(TempStringPointer); + + TempStringPointer = ConvertDevicePathToText(DevicePath, TRUE, FALSE); + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DH_OUTPUT_DRIVER2), + gShellDriver1HiiHandle, + TempStringPointer!=NULL?TempStringPointer:L"", + ParentControllerHandleCount == 0?L"ROOT":(ChildControllerHandleCount > 0)?L"BUS":L"DEVICE", + ConfigurationStatus?L"YES":L"NO", + DiagnosticsStatus?L"YES":L"NO" + ); + + SHELL_FREE_NON_NULL(TempStringPointer); + + if (DriverBindingHandleCount == 0) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DH_OUTPUT_DRIVER3), + gShellDriver1HiiHandle, + L"" + ); + } else { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DH_OUTPUT_DRIVER3), + gShellDriver1HiiHandle, + L"" + ); + for (Index = 0; Index < DriverBindingHandleCount; Index++) { + Image = FALSE; + Status = GetDriverName ( + DriverBindingHandleBuffer[Index], + Language, + &DriverName + ); + if (EFI_ERROR (Status)) { + Status = GetDriverImageName ( + DriverBindingHandleBuffer[Index], + &DriverName + ); + if (EFI_ERROR (Status)) { + DriverName = NULL; + } + } + + if (Image) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DH_OUTPUT_DRIVER4A), + gShellDriver1HiiHandle, + ConvertHandleToHandleIndex (DriverBindingHandleBuffer[Index]), + DriverName!=NULL?DriverName:L"" + ); + } else { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DH_OUTPUT_DRIVER4B), + gShellDriver1HiiHandle, + ConvertHandleToHandleIndex (DriverBindingHandleBuffer[Index]), + DriverName!=NULL?DriverName:L"" + ); + } + SHELL_FREE_NON_NULL(DriverName); + } + } + + if (ParentControllerHandleCount == 0) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DH_OUTPUT_DRIVER5), + gShellDriver1HiiHandle, + L"" + ); + } else { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DH_OUTPUT_DRIVER5), + gShellDriver1HiiHandle, + L"" + ); + for (Index = 0; Index < ParentControllerHandleCount; Index++) { + Status = gEfiShellProtocol->GetDeviceName(ParentControllerHandleBuffer[Index], EFI_DEVICE_NAME_USE_COMPONENT_NAME|EFI_DEVICE_NAME_USE_DEVICE_PATH, (CHAR8*)Language, &TempStringPointer); + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DH_OUTPUT_DRIVER5B), + gShellDriver1HiiHandle, + ConvertHandleToHandleIndex (ParentControllerHandleBuffer[Index]), + TempStringPointer!=NULL?TempStringPointer:L"" + ); + SHELL_FREE_NON_NULL(TempStringPointer); + } + } + + if (ChildControllerHandleCount == 0) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DH_OUTPUT_DRIVER6), + gShellDriver1HiiHandle, + L"" + ); + } else { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DH_OUTPUT_DRIVER6), + gShellDriver1HiiHandle, + L"" + ); + for (Index = 0; Index < ChildControllerHandleCount; Index++) { + Status = gEfiShellProtocol->GetDeviceName(ChildControllerHandleBuffer[Index], EFI_DEVICE_NAME_USE_COMPONENT_NAME|EFI_DEVICE_NAME_USE_DEVICE_PATH, (CHAR8*)Language, &TempStringPointer); + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DH_OUTPUT_DRIVER6B), + gShellDriver1HiiHandle, + ConvertHandleToHandleIndex (ChildControllerHandleBuffer[Index]), + TempStringPointer!=NULL?TempStringPointer:L"" + ); + SHELL_FREE_NON_NULL(TempStringPointer); + } + } + } + + SHELL_FREE_NON_NULL(DriverBindingHandleBuffer); + + SHELL_FREE_NON_NULL(ParentControllerHandleBuffer); + + SHELL_FREE_NON_NULL(ChildControllerHandleBuffer); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // See if Handle is a driver binding handle and display its details. + // + Status = gBS->OpenProtocol ( + Handle, + &gEfiDriverBindingProtocolGuid, + (VOID **) &DriverBinding, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + + NumberOfChildren = 0; + ControllerHandleBuffer = NULL; + Status = PARSE_HANDLE_DATABASE_DEVICES ( + Handle, + &ControllerHandleCount, + &ControllerHandleBuffer + ); + if (ControllerHandleCount > 0) { + for (HandleIndex = 0; HandleIndex < ControllerHandleCount; HandleIndex++) { + Status = PARSE_HANDLE_DATABASE_MANAGED_CHILDREN ( + Handle, + ControllerHandleBuffer[HandleIndex], + &ChildControllerHandleCount, + NULL + ); + NumberOfChildren += ChildControllerHandleCount; + } + } + + Status = GetDriverName (Handle, Language, &DriverName); + if (EFI_ERROR (Status)) { + DriverName = NULL; + } + + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DH_OUTPUT_DRIVER7), + gShellDriver1HiiHandle, + ConvertHandleToHandleIndex(Handle), + DriverName!=NULL?DriverName:L"" + ); + SHELL_FREE_NON_NULL(DriverName); + Status = GetDriverImageName ( + Handle, + &DriverName + ); + if (EFI_ERROR (Status)) { + DriverName = NULL; + } + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DH_OUTPUT_DRIVER7B), + gShellDriver1HiiHandle, + DriverName!=NULL?DriverName:L"" + ); + SHELL_FREE_NON_NULL(DriverName); + + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DH_OUTPUT_DRIVER8), + gShellDriver1HiiHandle, + DriverBinding->Version, + NumberOfChildren > 0?L"Bus":ControllerHandleCount > 0?L"Device":L"", + ConfigurationStatus?L"YES":L"NO", + DiagnosticsStatus?L"YES":L"NO" + ); + + if (ControllerHandleCount == 0) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DH_OUTPUT_DRIVER9), + gShellDriver1HiiHandle, + L"None" + ); + } else { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DH_OUTPUT_DRIVER9), + gShellDriver1HiiHandle, + L"" + ); + for (HandleIndex = 0; HandleIndex < ControllerHandleCount; HandleIndex++) { + Status = gEfiShellProtocol->GetDeviceName(ControllerHandleBuffer[HandleIndex], EFI_DEVICE_NAME_USE_COMPONENT_NAME|EFI_DEVICE_NAME_USE_DEVICE_PATH, (CHAR8*)Language, &TempStringPointer); + + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DH_OUTPUT_DRIVER9B), + gShellDriver1HiiHandle, + ConvertHandleToHandleIndex(ControllerHandleBuffer[HandleIndex]), + TempStringPointer!=NULL?TempStringPointer:L"" + ); + SHELL_FREE_NON_NULL(TempStringPointer); + + Status = PARSE_HANDLE_DATABASE_MANAGED_CHILDREN ( + Handle, + ControllerHandleBuffer[HandleIndex], + &ChildControllerHandleCount, + &ChildControllerHandleBuffer + ); + if (!EFI_ERROR (Status)) { + for (ChildIndex = 0; ChildIndex < ChildControllerHandleCount; ChildIndex++) { + Status = gEfiShellProtocol->GetDeviceName(ChildControllerHandleBuffer[ChildIndex], EFI_DEVICE_NAME_USE_COMPONENT_NAME|EFI_DEVICE_NAME_USE_DEVICE_PATH, (CHAR8*)Language, &TempStringPointer); + + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DH_OUTPUT_DRIVER6C), + gShellDriver1HiiHandle, + ConvertHandleToHandleIndex(ChildControllerHandleBuffer[ChildIndex]), + TempStringPointer!=NULL?TempStringPointer:L"" + ); + SHELL_FREE_NON_NULL(TempStringPointer); + } + + SHELL_FREE_NON_NULL (ChildControllerHandleBuffer); + } + } + + SHELL_FREE_NON_NULL (ControllerHandleBuffer); + } + + return EFI_SUCCESS; +} + +/** + Display information for a handle. + + @param[in] TheHandle The handles to show info on. + @param[in] Verbose TRUE for extra info, FALSE otherwise. + @param[in] Sfo TRUE to output in standard format output (spec). + @param[in] Language Language string per UEFI specification. + @param[in] DriverInfo TRUE to show all info about the handle. + @param[in] Multiple TRUE indicates more than will be output, + FALSE for a single one. +**/ +VOID +DoDhByHandle( + IN CONST EFI_HANDLE TheHandle, + IN CONST BOOLEAN Verbose, + IN CONST BOOLEAN Sfo, + IN CONST CHAR8 *Language, + IN CONST BOOLEAN DriverInfo, + IN CONST BOOLEAN Multiple + ) +{ + CHAR16 *ProtocolInfoString; + + ProtocolInfoString = NULL; + + if (!Sfo) { + if (Multiple) { + ProtocolInfoString = GetProtocolInfoString(TheHandle, Language, L" ", Verbose, TRUE); + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DH_OUTPUT), + gShellDriver1HiiHandle, + ConvertHandleToHandleIndex(TheHandle), + ProtocolInfoString==NULL?L"":ProtocolInfoString + ); + } else { + ProtocolInfoString = GetProtocolInfoString(TheHandle, Language, Verbose ? L"\r\n" : L" ", Verbose, TRUE); + if (Verbose) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DH_OUTPUT_SINGLE), + gShellDriver1HiiHandle, + ConvertHandleToHandleIndex(TheHandle), + TheHandle, + ProtocolInfoString==NULL?L"":ProtocolInfoString + ); + } else { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DH_OUTPUT_SINGLE_D), + gShellDriver1HiiHandle, + ConvertHandleToHandleIndex(TheHandle), + ProtocolInfoString==NULL?L"":ProtocolInfoString + ); + } + } + + if (DriverInfo) { + DisplayDriverModelHandle ((EFI_HANDLE)TheHandle, TRUE, Language); + } + } else { + ProtocolInfoString = GetProtocolInfoString(TheHandle, Language, L";", FALSE, FALSE); + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DH_OUTPUT_SFO), + gShellDriver1HiiHandle, + Multiple ?L"HandlesInfo":L"HandleInfo", + L"DriverName", + L"ControllerName", + ConvertHandleToHandleIndex(TheHandle), + L"DevPath", + ProtocolInfoString==NULL?L"":ProtocolInfoString + ); + } + + if (ProtocolInfoString != NULL) { + FreePool(ProtocolInfoString); + } +} + +/** + Display information for all handles on a list. + + @param[in] HandleList The NULL-terminated list of handles. + @param[in] Verbose TRUE for extra info, FALSE otherwise. + @param[in] Sfo TRUE to output in standard format output (spec). + @param[in] Language Language string per UEFI specification. + @param[in] DriverInfo TRUE to show all info about the handle. + + @retval SHELL_SUCCESS The operation was successful. + @retval SHELL_ABORTED The operation was aborted. +**/ +SHELL_STATUS +DoDhForHandleList( + IN CONST EFI_HANDLE *HandleList, + IN CONST BOOLEAN Verbose, + IN CONST BOOLEAN Sfo, + IN CONST CHAR8 *Language, + IN CONST BOOLEAN DriverInfo + ) +{ + CONST EFI_HANDLE *HandleWalker; + SHELL_STATUS ShellStatus; + + ShellStatus = SHELL_SUCCESS; + for (HandleWalker = HandleList; HandleWalker != NULL && *HandleWalker != NULL; HandleWalker++) { + DoDhByHandle (*HandleWalker, Verbose, Sfo, Language, DriverInfo, TRUE); + if (ShellGetExecutionBreakFlag ()) { + ShellStatus = SHELL_ABORTED; + break; + } + } + return (ShellStatus); +} + +/** + Display information for a GUID of protocol. + + @param[in] Guid The pointer to the name of the protocol. + @param[in] Verbose TRUE for extra info, FALSE otherwise. + @param[in] Sfo TRUE to output in standard format output (spec). + @param[in] Language Language string per UEFI specification. + @param[in] DriverInfo TRUE to show all info about the handle. + + @retval SHELL_SUCCESS The operation was successful. + @retval SHELL_NOT_FOUND The GUID was not found. + @retval SHELL_INVALID_PARAMETER ProtocolName was NULL or invalid. +**/ +SHELL_STATUS +DoDhByProtocolGuid( + IN CONST GUID *Guid, + IN CONST BOOLEAN Verbose, + IN CONST BOOLEAN Sfo, + IN CONST CHAR8 *Language, + IN CONST BOOLEAN DriverInfo + ) +{ + CHAR16 *Name; + SHELL_STATUS ShellStatus; + EFI_HANDLE *HandleList; + + if (!Sfo) { + if (Guid == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DH_OUTPUT_ALL_HEADER), gShellDriver1HiiHandle); + } else { + Name = GetStringNameFromGuid (Guid, NULL); + if (Name == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DH_OUTPUT_GUID_HEADER), gShellDriver1HiiHandle, Guid); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DH_OUTPUT_NAME_HEADER), gShellDriver1HiiHandle, Name); + } + } + } + HandleList = GetHandleListByProtocol(Guid); + ShellStatus = DoDhForHandleList(HandleList, Verbose, Sfo, Language, DriverInfo); + SHELL_FREE_NON_NULL(HandleList); + + return ShellStatus; +} + +/** + Function to determine use which method to print information. + If Protocol is NULL, The function will print all information. + + @param[in] Protocol The pointer to the name or GUID of protocol or NULL. + @param[in] Verbose TRUE for extra info, FALSE otherwise. + @param[in] Sfo TRUE to output in standard format output (spec). + @param[in] Language Language string per UEFI specification. + @param[in] DriverInfo TRUE to show all info about the handle. + + @retval SHELL_SUCCESS The operation was successful. + @retval SHELL_NOT_FOUND The protocol was not found. + @retval SHELL_INVALID_PARAMETER Protocol is invalid parameter. +**/ +SHELL_STATUS +DoDhByProtocol ( + IN CONST CHAR16 *Protocol, + IN CONST BOOLEAN Verbose, + IN CONST BOOLEAN Sfo, + IN CONST CHAR8 *Language, + IN CONST BOOLEAN DriverInfo + ) +{ + EFI_GUID Guid; + EFI_GUID *GuidPtr; + EFI_STATUS Status; + + if (Protocol == NULL) { + return DoDhByProtocolGuid (NULL, Verbose, Sfo, Language, DriverInfo); + } else { + Status = ConvertStrToGuid (Protocol, &Guid); + if (!EFI_ERROR (Status)) { + GuidPtr = &Guid; + } else { + // + // Protocol is a Name, convert it to GUID + // + Status = GetGuidFromStringName (Protocol, Language, &GuidPtr); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DH_NO_NAME_FOUND), gShellDriver1HiiHandle, Protocol); + return (SHELL_NOT_FOUND); + } + } + + return DoDhByProtocolGuid (GuidPtr, Verbose, Sfo, Language, DriverInfo); + } +} + +/** + Function to display decode information by Protocol. + The parameter Protocol is either a GUID or the name of protocol. + If the parameter Protocol is NULL, the function will print all + decode information. + + @param[in] Protocol The pointer to the name or GUID of protocol. + @param[in] Language Language string per UEFI specification. + + @retval SHELL_SUCCESS The operation was successful. + @retval SHELL_OUT_OT_RESOURCES A memory allocation failed. +**/ +SHELL_STATUS +DoDecodeByProtocol( + IN CONST CHAR16 *Protocol, + IN CONST CHAR8 *Language + ) +{ + EFI_STATUS Status; + EFI_GUID *Guids; + EFI_GUID Guid; + UINTN Counts; + UINTN Index; + CHAR16 *Name; + + if (Protocol == NULL) { + Counts = 0; + Status = GetAllMappingGuids (NULL, &Counts); + if (Status == EFI_BUFFER_TOO_SMALL) { + Guids = AllocatePool (Counts * sizeof(EFI_GUID)); + if (Guids == NULL) { + return SHELL_OUT_OF_RESOURCES; + } + + Status = GetAllMappingGuids (Guids, &Counts); + if (Status == EFI_SUCCESS) { + for (Index = 0; Index < Counts; Index++) { + Name = GetStringNameFromGuid (&Guids[Index], Language); + if (Name != NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DH_OUTPUT_DECODE), gShellDriver1HiiHandle, Name, &Guids[Index]); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DH_NO_GUID_FOUND), gShellDriver1HiiHandle, &Guids[Index]); + } + SHELL_FREE_NON_NULL (Name); + } + } + FreePool (Guids); + } + } else { + if (ConvertStrToGuid (Protocol, &Guid) == EFI_SUCCESS) { + Name = GetStringNameFromGuid (&Guid, Language); + if (Name != NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DH_OUTPUT_DECODE), gShellDriver1HiiHandle, Name, &Guid); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DH_NO_GUID_FOUND), gShellDriver1HiiHandle, &Guid); + } + SHELL_FREE_NON_NULL(Name); + } else { + Status = GetGuidFromStringName (Protocol, Language, &Guids); + if (Status == EFI_SUCCESS) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DH_OUTPUT_DECODE), gShellDriver1HiiHandle, Protocol, Guids); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DH_NO_NAME_FOUND), gShellDriver1HiiHandle, Protocol); + } + } + } + + return SHELL_SUCCESS; +} + +/** + Function for 'dh' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunDh ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CHAR8 *Language; + CONST CHAR16 *Lang; + CONST CHAR16 *RawValue; + CONST CHAR16 *ProtocolVal; + BOOLEAN SfoFlag; + BOOLEAN DriverFlag; + BOOLEAN VerboseFlag; + UINT64 Intermediate; + EFI_HANDLE Handle; + + ShellStatus = SHELL_SUCCESS; + Status = EFI_SUCCESS; + Language = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDriver1HiiHandle, L"dh", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetCount(Package) > 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDriver1HiiHandle, L"dh"); + ShellCommandLineFreeVarList (Package); + return (SHELL_INVALID_PARAMETER); + } + + if (ShellCommandLineGetFlag(Package, L"-l")) { + Lang = ShellCommandLineGetValue(Package, L"-l"); + if (Lang != NULL) { + Language = AllocateZeroPool(StrSize(Lang)); + AsciiSPrint(Language, StrSize(Lang), "%S", Lang); + } else { + ASSERT(Language == NULL); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_GEN_NO_VALUE), gShellDriver1HiiHandle, L"dh", L"-l"); + ShellCommandLineFreeVarList(Package); + return (SHELL_INVALID_PARAMETER); + } + } else { + Language = AllocateZeroPool(10); + AsciiSPrint(Language, 10, "en-us"); + } + + SfoFlag = ShellCommandLineGetFlag (Package, L"-sfo"); + DriverFlag = ShellCommandLineGetFlag (Package, L"-d"); + VerboseFlag = (BOOLEAN)(ShellCommandLineGetFlag (Package, L"-v") || ShellCommandLineGetFlag (Package, L"-verbose")); + RawValue = ShellCommandLineGetRawValue (Package, 1); + ProtocolVal = ShellCommandLineGetValue (Package, L"-p"); + + if (RawValue == NULL) { + if (ShellCommandLineGetFlag (Package, L"-p") && (ProtocolVal == NULL)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDriver1HiiHandle, L"dh", L"-p"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // Print information by protocol, The ProtocolVal maybe is name or GUID or NULL. + // + ShellStatus = DoDhByProtocol (ProtocolVal, VerboseFlag, SfoFlag, Language, DriverFlag); + } + } else if ((RawValue != NULL) && + (gUnicodeCollation->StriColl(gUnicodeCollation, L"decode", (CHAR16 *) RawValue) == 0)) { + if (ShellCommandLineGetFlag (Package, L"-p") && (ProtocolVal == NULL)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDriver1HiiHandle, L"dh", L"-p"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // Print decode informatino by protocol. + // + ShellStatus = DoDecodeByProtocol (ProtocolVal, Language); + } + } else { + if (ShellCommandLineGetFlag (Package, L"-p")) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDriver1HiiHandle, L"dh"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = ShellConvertStringToUint64 (RawValue, &Intermediate, TRUE, FALSE); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"dh", RawValue); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Handle = ConvertHandleIndexToHandle ((UINTN) Intermediate); + if (Handle == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"dh", RawValue); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // Print information by handle. + // + DoDhByHandle (Handle, VerboseFlag, SfoFlag, Language, DriverFlag, FALSE); + } + } + } + } + + ShellCommandLineFreeVarList (Package); + SHELL_FREE_NON_NULL(Language); + } + + return (ShellStatus); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Disconnect.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Disconnect.c new file mode 100644 index 00000000..e209db89 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Disconnect.c @@ -0,0 +1,198 @@ +/** @file + Main file for Disconnect shell Driver1 function. + + (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+ (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDriver1CommandsLib.h" + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-r", TypeFlag}, + {L"-nc", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Disconnect everything. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +DisconnectAll( + VOID + ) +{ + // + // Stolen from UEFI 2.3 spec (May 2009 version) + // Pages 171/172 + // Removed gBS local definition + // + + // + // Disconnect All Handles Example + // The following example recusively disconnects all drivers from all + // controllers in a platform. + // + EFI_STATUS Status; +// EFI_BOOT_SERVICES *gBS; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN HandleIndex; + // + // Retrieve the list of all handles from the handle database + // + Status = gBS->LocateHandleBuffer ( + AllHandles, + NULL, + NULL, + &HandleCount, + &HandleBuffer + ); + if (!EFI_ERROR (Status)) { + for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) { + Status = gBS->DisconnectController ( + HandleBuffer[HandleIndex], + NULL, + NULL + ); + } + gBS->FreePool(HandleBuffer); + // + // end of stealing + // + } + return (EFI_SUCCESS); +} + +/** + Function for 'disconnect' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunDisconnect ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CONST CHAR16 *Param1; + CONST CHAR16 *Param2; + CONST CHAR16 *Param3; + EFI_HANDLE Handle1; + EFI_HANDLE Handle2; + EFI_HANDLE Handle3; + UINT64 Intermediate1; + UINT64 Intermediate2; + UINT64 Intermediate3; + + ShellStatus = SHELL_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDriver1HiiHandle, L"disconnect", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetFlag(Package, L"-r")){ + if (ShellCommandLineGetCount(Package) > 1){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDriver1HiiHandle, L"disconnect"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetCount(Package) < 1) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDriver1HiiHandle, L"disconnect"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = DisconnectAll (); + // + // Reconnect all consoles if -nc is not provided + // + if (!ShellCommandLineGetFlag (Package, L"-nc")){ + ShellConnectFromDevPaths (L"ConInDev"); + ShellConnectFromDevPaths (L"ConOutDev"); + ShellConnectFromDevPaths (L"ErrOutDev"); + ShellConnectFromDevPaths (L"ErrOut"); + ShellConnectFromDevPaths (L"ConIn"); + ShellConnectFromDevPaths (L"ConOut"); + } + } + } else if (ShellCommandLineGetFlag (Package, L"-nc")) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDriver1HiiHandle, L"disconnect"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + if (ShellCommandLineGetCount(Package) > 4){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDriver1HiiHandle, L"disconnect"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetCount(Package) < 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDriver1HiiHandle, L"disconnect"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // must have between 1 and 3 handles passed in ... + // + Param1 = ShellCommandLineGetRawValue(Package, 1); + Param2 = ShellCommandLineGetRawValue(Package, 2); + Param3 = ShellCommandLineGetRawValue(Package, 3); + ShellConvertStringToUint64(Param1, &Intermediate1, TRUE, FALSE); + Handle1 = Param1!=NULL?ConvertHandleIndexToHandle((UINTN)Intermediate1):NULL; + ShellConvertStringToUint64(Param2, &Intermediate2, TRUE, FALSE); + Handle2 = Param2!=NULL?ConvertHandleIndexToHandle((UINTN)Intermediate2):NULL; + ShellConvertStringToUint64(Param3, &Intermediate3, TRUE, FALSE); + Handle3 = Param3!=NULL?ConvertHandleIndexToHandle((UINTN)Intermediate3):NULL; + + if (Param1 != NULL && Handle1 == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"disconnect", Param1); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (Param2 != NULL && Handle2 == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"disconnect", Param2); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (Param3 != NULL && Handle3 == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"disconnect", Param3); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (Handle2 != NULL && EFI_ERROR(gBS->OpenProtocol(Handle2, &gEfiDriverBindingProtocolGuid, NULL, gImageHandle, NULL, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) { + ASSERT(Param2 != NULL); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_HANDLE_NOT), gShellDriver1HiiHandle, L"disconnect", ShellStrToUintn(Param2), L"driver handle"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(Param1 != NULL); + Status = gBS->DisconnectController(Handle1, Handle2, Handle3); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_3P_RESULT), gShellDriver1HiiHandle, L"Disconnect", (UINTN)Intermediate1, (UINTN)Intermediate2, (UINTN)Intermediate3, Status); + } + } + } + } + if (ShellStatus == SHELL_SUCCESS) { + if (Status == EFI_SECURITY_VIOLATION) { + ShellStatus = SHELL_SECURITY_VIOLATION; + } else if (Status == EFI_INVALID_PARAMETER) { + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (EFI_ERROR(Status)) { + ShellStatus = SHELL_NOT_FOUND; + } + } + return (ShellStatus); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Drivers.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Drivers.c new file mode 100644 index 00000000..cf8d3d32 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Drivers.c @@ -0,0 +1,423 @@ +/** @file + Main file for Drivers shell Driver1 function. + + (C) Copyright 2012-2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDriver1CommandsLib.h" + +#define MAX_LEN_DRIVER_NAME 35 + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-sfo", TypeFlag}, + {L"-l", TypeValue}, + {NULL, TypeMax} + }; + +/** + Get a device path (in text format) for a given handle. + + @param[in] TheHandle The handle to get the device path for. + + @retval NULL An error occurred. + @return A pointer to the driver path as a string. The callee must + free this memory. +**/ +CHAR16* +GetDevicePathTextForHandle( + IN EFI_HANDLE TheHandle + ) +{ + EFI_STATUS Status; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath; + EFI_DEVICE_PATH_PROTOCOL *FinalPath; + CHAR16 *RetVal; + + FinalPath = NULL; + + Status = gBS->OpenProtocol ( + TheHandle, + &gEfiLoadedImageProtocolGuid, + (VOID**)&LoadedImage, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + Status = gBS->OpenProtocol ( + LoadedImage->DeviceHandle, + &gEfiDevicePathProtocolGuid, + (VOID**)&ImageDevicePath, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + FinalPath = AppendDevicePath (ImageDevicePath, LoadedImage->FilePath); + gBS->CloseProtocol( + LoadedImage->DeviceHandle, + &gEfiDevicePathProtocolGuid, + gImageHandle, + NULL); + } + gBS->CloseProtocol( + TheHandle, + &gEfiLoadedImageProtocolGuid, + gImageHandle, + NULL); + } + + if (FinalPath == NULL) { + return (NULL); + } + RetVal = gEfiShellProtocol->GetFilePathFromDevicePath(FinalPath); + if (RetVal == NULL) { + RetVal = ConvertDevicePathToText(FinalPath, TRUE, TRUE); + } + FreePool(FinalPath); + return (RetVal); +} + +/** + Determine if the given handle has Driver Configuration protocol. + + @param[in] TheHandle The handle to the driver to test. + + @retval TRUE The driver does have Driver Configuration. + @retval FALSE The driver does not have Driver Configuration. +**/ +BOOLEAN +ReturnDriverConfig( + IN CONST EFI_HANDLE TheHandle + ) +{ + EFI_STATUS Status; + Status = gBS->OpenProtocol((EFI_HANDLE)TheHandle, &gEfiDriverConfigurationProtocolGuid, NULL, gImageHandle, NULL, EFI_OPEN_PROTOCOL_TEST_PROTOCOL); + if (EFI_ERROR(Status)) { + return (FALSE); + } + return (TRUE); +} + +/** + Determine if the given handle has DriverDiagnostics protocol. + + @param[in] TheHandle The handle to the driver to test. + + @retval TRUE The driver does have Driver Diasgnostics. + @retval FALSE The driver does not have Driver Diagnostics. +**/ +BOOLEAN +ReturnDriverDiag( + IN CONST EFI_HANDLE TheHandle + ) +{ + EFI_STATUS Status; + Status = gBS->OpenProtocol((EFI_HANDLE)TheHandle, &gEfiDriverDiagnostics2ProtocolGuid, NULL, gImageHandle, NULL, EFI_OPEN_PROTOCOL_TEST_PROTOCOL); + if (EFI_ERROR(Status)) { + Status = gBS->OpenProtocol((EFI_HANDLE)TheHandle, &gEfiDriverDiagnosticsProtocolGuid, NULL, gImageHandle, NULL, EFI_OPEN_PROTOCOL_TEST_PROTOCOL); + if (EFI_ERROR(Status)) { + return (FALSE); + } + } + return (TRUE); +} + +/** + Finds and returns the version of the driver specified by TheHandle. + + @param[in] TheHandle The driver handle to get the version of. + + @return The version of the driver. + @retval 0xFFFFFFFF An error ocurred. +**/ +UINT32 +ReturnDriverVersion( + IN CONST EFI_HANDLE TheHandle + ) +{ + EFI_DRIVER_BINDING_PROTOCOL *DriverBinding; + EFI_STATUS Status; + UINT32 RetVal; + + RetVal = (UINT32)-1; + + Status = gBS->OpenProtocol((EFI_HANDLE)TheHandle, &gEfiDriverBindingProtocolGuid, (VOID**)&DriverBinding, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (!EFI_ERROR(Status)) { + RetVal = DriverBinding->Version; + gBS->CloseProtocol(TheHandle, &gEfiDriverBindingProtocolGuid, gImageHandle, NULL); + } + return (RetVal); +} + +/** + Get image name from Image Handle. + + @param[in] Handle Image Handle + + @return A pointer to the image name as a string. +**/ +CHAR16 * +GetImageNameFromHandle ( + IN CONST EFI_HANDLE Handle + ) +{ + EFI_STATUS Status; + EFI_DRIVER_BINDING_PROTOCOL *DriverBinding; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + EFI_DEVICE_PATH_PROTOCOL *DevPathNode; + EFI_GUID *NameGuid; + CHAR16 *ImageName; + UINTN BufferSize; + UINT32 AuthenticationStatus; + EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv2; + + LoadedImage = NULL; + DriverBinding = NULL; + ImageName = NULL; + + Status = gBS->OpenProtocol ( + Handle, + &gEfiDriverBindingProtocolGuid, + (VOID **) &DriverBinding, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return NULL; + } + Status = gBS->OpenProtocol ( + DriverBinding->ImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID**)&LoadedImage, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + DevPathNode = LoadedImage->FilePath; + if (DevPathNode == NULL) { + return NULL; + } + while (!IsDevicePathEnd (DevPathNode)) { + NameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)DevPathNode); + if (NameGuid != NULL) { + Status = gBS->HandleProtocol ( + LoadedImage->DeviceHandle, + &gEfiFirmwareVolume2ProtocolGuid, + (VOID **)&Fv2 + ); + if (!EFI_ERROR (Status)) { + Status = Fv2->ReadSection ( + Fv2, + NameGuid, + EFI_SECTION_USER_INTERFACE, + 0, + (VOID **)&ImageName, + &BufferSize, + &AuthenticationStatus + ); + if (!EFI_ERROR (Status)) { + break; + } + ImageName = NULL; + } + } + // + // Next device path node + // + DevPathNode = NextDevicePathNode (DevPathNode); + } + if (ImageName == NULL) { + ImageName = ConvertDevicePathToText (LoadedImage->FilePath, TRUE, TRUE); + } + } + return ImageName; +} + +/** + Function for 'drivers' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunDrivers ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CHAR8 *Language; + CONST CHAR16 *Lang; + EFI_HANDLE *HandleList; + EFI_HANDLE *HandleWalker; + UINTN ChildCount; + UINTN DeviceCount; + CHAR16 ChildCountStr[21]; + CHAR16 DeviceCountStr[21]; + CHAR16 *Temp2; + CONST CHAR16 *FullDriverName; + CHAR16 *TruncatedDriverName; + CHAR16 *ImageName; + CHAR16 *FormatString; + UINT32 DriverVersion; + BOOLEAN DriverConfig; + BOOLEAN DriverDiag; + BOOLEAN SfoFlag; + + ShellStatus = SHELL_SUCCESS; + Status = EFI_SUCCESS; + Language = NULL; + FormatString = NULL; + SfoFlag = FALSE; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDriver1HiiHandle, L"drivers", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetCount(Package) > 1) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDriver1HiiHandle, L"drivers"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + if (ShellCommandLineGetFlag(Package, L"-l")){ + Lang = ShellCommandLineGetValue(Package, L"-l"); + if (Lang != NULL) { + Language = AllocateZeroPool(StrSize(Lang)); + AsciiSPrint(Language, StrSize(Lang), "%S", Lang); + } else { + ASSERT(Language == NULL); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDriver1HiiHandle, L"drivers", L"-l"); + ShellCommandLineFreeVarList (Package); + return (SHELL_INVALID_PARAMETER); + } + } + + if (ShellCommandLineGetFlag (Package, L"-sfo")) { + SfoFlag = TRUE; + FormatString = HiiGetString (gShellDriver1HiiHandle, STRING_TOKEN (STR_DRIVERS_ITEM_LINE_SFO), Language); + // + // print the SFO header + // + ShellPrintHiiEx ( + -1, + -1, + Language, + STRING_TOKEN (STR_GEN_SFO_HEADER), + gShellDriver1HiiHandle, + L"drivers"); + } else { + FormatString = HiiGetString (gShellDriver1HiiHandle, STRING_TOKEN (STR_DRIVERS_ITEM_LINE), Language); + // + // print the header row + // + ShellPrintHiiEx( + -1, + -1, + Language, + STRING_TOKEN (STR_DRIVERS_HEADER_LINES), + gShellDriver1HiiHandle); + } + + HandleList = GetHandleListByProtocol(&gEfiDriverBindingProtocolGuid); + for (HandleWalker = HandleList ; HandleWalker != NULL && *HandleWalker != NULL ; HandleWalker++){ + ChildCount = 0; + DeviceCount = 0; + Status = ParseHandleDatabaseForChildDevices (*HandleWalker, &ChildCount , NULL); + Status = PARSE_HANDLE_DATABASE_DEVICES (*HandleWalker, &DeviceCount, NULL); + Temp2 = GetDevicePathTextForHandle(*HandleWalker); + DriverVersion = ReturnDriverVersion(*HandleWalker); + DriverConfig = ReturnDriverConfig(*HandleWalker); + DriverDiag = ReturnDriverDiag (*HandleWalker); + FullDriverName = GetStringNameFromHandle(*HandleWalker, Language); + ImageName = GetImageNameFromHandle (*HandleWalker); + + UnicodeValueToStringS (ChildCountStr, sizeof (ChildCountStr), 0, ChildCount, 0); + UnicodeValueToStringS (DeviceCountStr, sizeof (DeviceCountStr), 0, DeviceCount, 0); + TruncatedDriverName = NULL; + if (!SfoFlag && (FullDriverName != NULL)) { + TruncatedDriverName = AllocateZeroPool ((MAX_LEN_DRIVER_NAME + 1) * sizeof (CHAR16)); + StrnCpyS (TruncatedDriverName, MAX_LEN_DRIVER_NAME + 1, FullDriverName, MAX_LEN_DRIVER_NAME); + } + + if (!SfoFlag) { + ShellPrintEx ( + -1, + -1, + FormatString, + ConvertHandleToHandleIndex (*HandleWalker), + DriverVersion, + ChildCount > 0 ? L'B' : (DeviceCount > 0 ? L'D' : L'?'), + DriverConfig ? L'X' : L'-', + DriverDiag ? L'X' : L'-', + DeviceCount > 0 ? DeviceCountStr : L"-", + ChildCount > 0 ? ChildCountStr : L"-", + TruncatedDriverName, + ImageName == NULL ? L"" : ImageName + ); + } else { + ShellPrintEx ( + -1, + -1, + FormatString, + ConvertHandleToHandleIndex (*HandleWalker), + DriverVersion, + ChildCount > 0 ? L'B' : (DeviceCount > 0 ? L'D' : L'?'), + DriverConfig ? L'Y' : L'N', + DriverDiag ? L'Y' : L'N', + DeviceCount, + ChildCount, + FullDriverName, + Temp2 == NULL ? L"" : Temp2 + ); + } + if (TruncatedDriverName != NULL) { + FreePool (TruncatedDriverName); + } + if (Temp2 != NULL) { + FreePool(Temp2); + } + if (ImageName != NULL) { + FreePool (ImageName); + } + + if (ShellGetExecutionBreakFlag ()) { + ShellStatus = SHELL_ABORTED; + break; + } + } + } + SHELL_FREE_NON_NULL(Language); + ShellCommandLineFreeVarList (Package); + SHELL_FREE_NON_NULL(FormatString); + } + + return (ShellStatus); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/DrvCfg.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/DrvCfg.c new file mode 100644 index 00000000..4259f451 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/DrvCfg.c @@ -0,0 +1,1406 @@ +/** @file + Main file for DrvCfg shell Driver1 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDriver1CommandsLib.h" +#include +#include + +STATIC CONST EFI_GUID *CfgGuidList[] = {&gEfiDriverConfigurationProtocolGuid, &gEfiDriverConfiguration2ProtocolGuid, NULL}; + +/** + Find the EFI_HII_HANDLE by device path. + + @param[in] DevPath1 The Device Path to match. + @param[out] HiiHandle The EFI_HII_HANDLE after the converstion. + @param[in] HiiDb The Hii database protocol + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_NOT_FOUND There was no EFI_HII_HANDLE found for that deviec path. +**/ +EFI_STATUS +FindHiiHandleViaDevPath( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevPath1, + OUT EFI_HII_HANDLE *HiiHandle, + IN EFI_HII_DATABASE_PROTOCOL *HiiDb + ) +{ + EFI_HII_HANDLE *HandleBuffer; + UINTN HandleBufferSize; + VOID *MainBuffer; + UINTN MainBufferSize; + EFI_HII_PACKAGE_LIST_HEADER *PackageListHeader; + EFI_HII_PACKAGE_HEADER *PackageHeader; + UINTN LoopVariable; + EFI_DEVICE_PATH_PROTOCOL *DevPath2; + EFI_STATUS Status; + + ASSERT(DevPath1 != NULL); + ASSERT(HiiHandle != NULL); + ASSERT(*HiiHandle == NULL); + ASSERT(HiiDb != NULL); + + HandleBufferSize = 0; + HandleBuffer = NULL; + Status = HiiDb->ListPackageLists(HiiDb, EFI_HII_PACKAGE_DEVICE_PATH, NULL, &HandleBufferSize, HandleBuffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + HandleBuffer = AllocateZeroPool(HandleBufferSize); + if (HandleBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + Status = HiiDb->ListPackageLists (HiiDb, EFI_HII_PACKAGE_DEVICE_PATH, NULL, &HandleBufferSize, HandleBuffer); + } + } + if (EFI_ERROR(Status)) { + SHELL_FREE_NON_NULL(HandleBuffer); + return (Status); + } + + if (HandleBuffer == NULL) { + return EFI_NOT_FOUND; + } + + for (LoopVariable = 0 ; LoopVariable < (HandleBufferSize/sizeof(HandleBuffer[0])) && *HiiHandle == NULL ; LoopVariable++) { + MainBufferSize = 0; + MainBuffer = NULL; + Status = HiiDb->ExportPackageLists(HiiDb, HandleBuffer[LoopVariable], &MainBufferSize, MainBuffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + MainBuffer = AllocateZeroPool(MainBufferSize); + if (MainBuffer != NULL) { + Status = HiiDb->ExportPackageLists (HiiDb, HandleBuffer[LoopVariable], &MainBufferSize, MainBuffer); + } + } + if (EFI_ERROR (Status)) { + continue; + } + // + // Enumerate through the block of returned memory. + // This should actually be a small block, but we need to be sure. + // + for (PackageListHeader = (EFI_HII_PACKAGE_LIST_HEADER*)MainBuffer + ; PackageListHeader != NULL && ((CHAR8*)PackageListHeader) < (((CHAR8*)MainBuffer)+MainBufferSize) && *HiiHandle == NULL + ; PackageListHeader = (EFI_HII_PACKAGE_LIST_HEADER*)(((CHAR8*)(PackageListHeader)) + PackageListHeader->PackageLength )) { + for (PackageHeader = (EFI_HII_PACKAGE_HEADER*)(((CHAR8*)(PackageListHeader))+sizeof(EFI_HII_PACKAGE_LIST_HEADER)) + ; PackageHeader != NULL && ((CHAR8*)PackageHeader) < (((CHAR8*)MainBuffer)+MainBufferSize) && PackageHeader->Type != EFI_HII_PACKAGE_END && *HiiHandle == NULL + ; PackageHeader = (EFI_HII_PACKAGE_HEADER*)(((CHAR8*)(PackageHeader))+PackageHeader->Length)) { + if (PackageHeader->Type == EFI_HII_PACKAGE_DEVICE_PATH) { + DevPath2 = (EFI_DEVICE_PATH_PROTOCOL*)(((CHAR8*)PackageHeader) + sizeof(EFI_HII_PACKAGE_HEADER)); + if (DevicePathCompare(&DevPath1, &DevPath2) == 0) { + *HiiHandle = HandleBuffer[LoopVariable]; + break; + } + } + } + } + SHELL_FREE_NON_NULL(MainBuffer); + } + SHELL_FREE_NON_NULL(HandleBuffer); + + if (*HiiHandle == NULL) { + return (EFI_NOT_FOUND); + } + return (EFI_SUCCESS); +} + +/** + Convert a EFI_HANDLE to a EFI_HII_HANDLE. + + @param[in] Handle The EFI_HANDLE to convert. + @param[out] HiiHandle The EFI_HII_HANDLE after the converstion. + @param[in] HiiDb The Hii database protocol + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ConvertHandleToHiiHandle( + IN CONST EFI_HANDLE Handle, + OUT EFI_HII_HANDLE *HiiHandle, + IN EFI_HII_DATABASE_PROTOCOL *HiiDb + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevPath1; + + if (HiiHandle == NULL || HiiDb == NULL) { + return (EFI_INVALID_PARAMETER); + } + *HiiHandle = NULL; + + if (Handle == NULL) { + return (EFI_SUCCESS); + } + + DevPath1 = NULL; + Status = gBS->OpenProtocol(Handle, &gEfiDevicePathProtocolGuid, (VOID**)&DevPath1, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(Status) || DevPath1 == NULL) { + return (EFI_NOT_FOUND); + } + + return (FindHiiHandleViaDevPath(DevPath1, HiiHandle, HiiDb)); +} + +/** + Function to print out all HII configuration information to a file. + + @param[in] Handle The handle to get info on. NULL to do all handles. + @param[in] FileName The filename to rwite the info to. +**/ +SHELL_STATUS +ConfigToFile( + IN CONST EFI_HANDLE Handle, + IN CONST CHAR16 *FileName + ) +{ + EFI_HII_DATABASE_PROTOCOL *HiiDatabase; + EFI_STATUS Status; + VOID *MainBuffer; + UINTN MainBufferSize; + EFI_HII_HANDLE HiiHandle; + SHELL_FILE_HANDLE FileHandle; + + HiiDatabase = NULL; + MainBufferSize = 0; + MainBuffer = NULL; + FileHandle = NULL; + + Status = ShellOpenFileByName(FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN(STR_GEN_FILE_OPEN_FAIL), + gShellDriver1HiiHandle, + L"drvcfg", + FileName, + Status); + return (SHELL_DEVICE_ERROR); + } + + // + // Locate HII Database protocol + // + Status = gBS->LocateProtocol ( + &gEfiHiiDatabaseProtocolGuid, + NULL, + (VOID **) &HiiDatabase + ); + + if (EFI_ERROR(Status) || HiiDatabase == NULL) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN(STR_GEN_PROTOCOL_NF), + gShellDriver1HiiHandle, + L"drvcfg", + L"EfiHiiDatabaseProtocol", + &gEfiHiiDatabaseProtocolGuid); + ShellCloseFile(&FileHandle); + return (SHELL_NOT_FOUND); + } + + HiiHandle = NULL; + Status = ConvertHandleToHiiHandle(Handle, &HiiHandle, HiiDatabase); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN(STR_GEN_HANDLE_NOT), + gShellDriver1HiiHandle, + L"drvcfg", + ConvertHandleToHandleIndex(Handle), + L"Device"); + ShellCloseFile(&FileHandle); + return (SHELL_DEVICE_ERROR); + } + + Status = HiiDatabase->ExportPackageLists(HiiDatabase, HiiHandle, &MainBufferSize, MainBuffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + MainBuffer = AllocateZeroPool(MainBufferSize); + Status = HiiDatabase->ExportPackageLists(HiiDatabase, HiiHandle, &MainBufferSize, MainBuffer); + } + + Status = ShellWriteFile(FileHandle, &MainBufferSize, MainBuffer); + + ShellCloseFile(&FileHandle); + SHELL_FREE_NON_NULL(MainBuffer); + + if (EFI_ERROR(Status)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN(STR_FILE_WRITE_FAIL), + gShellDriver1HiiHandle, + L"drvcfg", + FileName); + return (SHELL_DEVICE_ERROR); + } + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN(STR_DRVCFG_COMP), + gShellDriver1HiiHandle); + + return (SHELL_SUCCESS); +} + +/** + Function to read in HII configuration information from a file. + + @param[in] Handle The handle to get info for. + @param[in] FileName The filename to read the info from. +**/ +SHELL_STATUS +ConfigFromFile( + IN EFI_HANDLE Handle, + IN CONST CHAR16 *FileName + ) +{ + EFI_HII_DATABASE_PROTOCOL *HiiDatabase; + EFI_STATUS Status; + VOID *MainBuffer; + UINT64 Temp; + UINTN MainBufferSize; + EFI_HII_HANDLE HiiHandle; + SHELL_FILE_HANDLE FileHandle; + CHAR16 *TempDevPathString; + EFI_HII_PACKAGE_LIST_HEADER *PackageListHeader; + EFI_HII_PACKAGE_HEADER *PackageHeader; + EFI_DEVICE_PATH_PROTOCOL *DevPath; + UINTN HandleIndex; + + HiiDatabase = NULL; + MainBufferSize = 0; + MainBuffer = NULL; + FileHandle = NULL; + + Status = ShellOpenFileByName(FileName, &FileHandle, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN(STR_GEN_FILE_OPEN_FAIL), + gShellDriver1HiiHandle, + L"drvcfg", + FileName, + Status); + return (SHELL_DEVICE_ERROR); + } + + // + // Locate HII Database protocol + // + Status = gBS->LocateProtocol ( + &gEfiHiiDatabaseProtocolGuid, + NULL, + (VOID **) &HiiDatabase + ); + + if (EFI_ERROR(Status) || HiiDatabase == NULL) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN(STR_GEN_PROTOCOL_NF), + gShellDriver1HiiHandle, + L"drvcfg", + L"EfiHiiDatabaseProtocol", + &gEfiHiiDatabaseProtocolGuid); + ShellCloseFile(&FileHandle); + return (SHELL_NOT_FOUND); + } + + Status = ShellGetFileSize(FileHandle, &Temp); + MainBufferSize = (UINTN)Temp; + if (EFI_ERROR(Status)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN(STR_FILE_READ_FAIL), + gShellDriver1HiiHandle, + L"drvcfg", + FileName); + + ShellCloseFile(&FileHandle); + return (SHELL_DEVICE_ERROR); + } + MainBuffer = AllocateZeroPool((UINTN)MainBufferSize); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN(STR_GEN_OUT_MEM), + gShellDriver1HiiHandle, L"drvcfg"); + ShellCloseFile(&FileHandle); + return (SHELL_DEVICE_ERROR); + } + Status = ShellReadFile(FileHandle, &MainBufferSize, MainBuffer); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN(STR_FILE_READ_FAIL), + gShellDriver1HiiHandle, + L"drvcfg", + FileName); + + ShellCloseFile(&FileHandle); + SHELL_FREE_NON_NULL(MainBuffer); + return (SHELL_DEVICE_ERROR); + } + + ShellCloseFile(&FileHandle); + + if (Handle != NULL) { + // + // User override in place. Just do it. + // + HiiHandle = NULL; + Status = ConvertHandleToHiiHandle(Handle, &HiiHandle, HiiDatabase); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN(STR_GEN_HANDLE_NOT), + gShellDriver1HiiHandle, L"drvcfg", + ConvertHandleToHandleIndex(Handle), + L"Device"); + ShellCloseFile(&FileHandle); + return (SHELL_DEVICE_ERROR); + } + Status = HiiDatabase->UpdatePackageList(HiiDatabase, HiiHandle, MainBuffer); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN(STR_GEN_UEFI_FUNC_WARN), + gShellDriver1HiiHandle, + L"drvcfg", + L"HiiDatabase->UpdatePackageList", + Status); + return (SHELL_DEVICE_ERROR); + } + } else { + // + // we need to parse the buffer and try to match the device paths for each item to try to find it's device path. + // + + for (PackageListHeader = (EFI_HII_PACKAGE_LIST_HEADER*)MainBuffer + ; PackageListHeader != NULL && ((CHAR8*)PackageListHeader) < (((CHAR8*)MainBuffer)+MainBufferSize) + ; PackageListHeader = (EFI_HII_PACKAGE_LIST_HEADER*)(((CHAR8*)(PackageListHeader)) + PackageListHeader->PackageLength )) { + for (PackageHeader = (EFI_HII_PACKAGE_HEADER*)(((CHAR8*)(PackageListHeader))+sizeof(EFI_HII_PACKAGE_LIST_HEADER)) + ; PackageHeader != NULL && ((CHAR8*)PackageHeader) < (((CHAR8*)MainBuffer)+MainBufferSize) && PackageHeader->Type != EFI_HII_PACKAGE_END + ; PackageHeader = (EFI_HII_PACKAGE_HEADER*)(((CHAR8*)(PackageHeader))+PackageHeader->Length)) { + if (PackageHeader->Type == EFI_HII_PACKAGE_DEVICE_PATH) { + HiiHandle = NULL; + Status = FindHiiHandleViaDevPath((EFI_DEVICE_PATH_PROTOCOL*)(((CHAR8*)PackageHeader) + sizeof(EFI_HII_PACKAGE_HEADER)), &HiiHandle, HiiDatabase); + if (EFI_ERROR(Status)) { + // + // print out an error. + // + TempDevPathString = ConvertDevicePathToText((EFI_DEVICE_PATH_PROTOCOL*)(((CHAR8*)PackageHeader) + sizeof(EFI_HII_PACKAGE_HEADER)), TRUE, TRUE); + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN(STR_DRVCFG_IN_FILE_NF), + gShellDriver1HiiHandle, + TempDevPathString); + SHELL_FREE_NON_NULL(TempDevPathString); + } else { + Status = HiiDatabase->UpdatePackageList(HiiDatabase, HiiHandle, PackageListHeader); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN(STR_GEN_UEFI_FUNC_WARN), + gShellDriver1HiiHandle, + L"drvcfg", + L"HiiDatabase->UpdatePackageList", + Status); + return (SHELL_DEVICE_ERROR); + } else { + DevPath = (EFI_DEVICE_PATH_PROTOCOL*)(((CHAR8*)PackageHeader) + sizeof(EFI_HII_PACKAGE_HEADER)); + gBS->LocateDevicePath(&gEfiHiiConfigAccessProtocolGuid, &DevPath, &Handle); + HandleIndex = ConvertHandleToHandleIndex(Handle); + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN(STR_DRVCFG_DONE_HII), + gShellDriver1HiiHandle, + HandleIndex); + } + } + } + } + } + } + + SHELL_FREE_NON_NULL(MainBuffer); + + + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN(STR_DRVCFG_COMP), + gShellDriver1HiiHandle); + return (SHELL_SUCCESS); +} + +/** + Present a requested action to the user. + + @param[in] DriverImageHandle The handle for the driver to configure. + @param[in] ControllerHandle The handle of the device being managed by the Driver specified. + @param[in] ChildHandle The handle of a child device of the specified device. + @param[in] ActionRequired The required HII action. + + @retval SHELL_INVALID_PARAMETER A parameter has a invalid value. +**/ +EFI_STATUS +ShellCmdDriverConfigurationProcessActionRequired ( + EFI_HANDLE DriverImageHandle, + EFI_HANDLE ControllerHandle, + EFI_HANDLE ChildHandle, + EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED ActionRequired + ) +{ + EFI_HANDLE ConnectControllerContextOverride[2]; + + switch (ActionRequired) { + case EfiDriverConfigurationActionNone: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_DRVCFG_NONE), gShellDriver1HiiHandle); + break; + + case EfiDriverConfigurationActionStopController: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_DRVCFG_STOP), gShellDriver1HiiHandle); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_DRVCFG_ENTER_S), gShellDriver1HiiHandle, L"stop controller"); + ShellPromptForResponse(ShellPromptResponseTypeEnterContinue, NULL, NULL); + + gBS->DisconnectController (ControllerHandle, DriverImageHandle, ChildHandle); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_DRVCFG_CTLR_S), gShellDriver1HiiHandle, L"stopped"); + break; + + case EfiDriverConfigurationActionRestartController: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_DRVCFG_RESTART_S), gShellDriver1HiiHandle, L"controller"); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_DRVCFG_ENTER_S), gShellDriver1HiiHandle, L"restart controller"); + ShellPromptForResponse(ShellPromptResponseTypeEnterContinue, NULL, NULL); + + gBS->DisconnectController (ControllerHandle, DriverImageHandle, ChildHandle); + ConnectControllerContextOverride[0] = DriverImageHandle; + ConnectControllerContextOverride[1] = NULL; + gBS->ConnectController (ControllerHandle, ConnectControllerContextOverride, NULL, TRUE); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_DRVCFG_CTLR_S), gShellDriver1HiiHandle, L"restarted"); + break; + + case EfiDriverConfigurationActionRestartPlatform: + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_DRVCFG_RESTART_S), gShellDriver1HiiHandle, L"platform"); + ShellPrintHiiEx(-1,-1,NULL,STRING_TOKEN (STR_DRVCFG_ENTER_S), gShellDriver1HiiHandle, L"restart platform"); + ShellPromptForResponse(ShellPromptResponseTypeEnterContinue, NULL, NULL); + + gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL); + break; + + default: + return (EFI_INVALID_PARAMETER); + } + + return EFI_SUCCESS; +} + +/** + Do the configuration in an environment without HII. + + @param[in] Language The language code. + @param[in] ForceDefaults TRUE to force defaults, FALSE otherwise. + @param[in] DefaultType If ForceDefaults is TRUE, specifies the default type. + @param[in] AllChildren TRUE to configure all children, FALSE otherwise. + @param[in] ValidateOptions TRUE to validate existing options, FALSE otherwise. + @param[in] SetOptions TRUE to set options, FALSE otherwise. + @param[in] DriverImageHandle The handle for the driver to configure. + @param[in] DeviceHandle The handle of the device being managed by the Driver specified. + @param[in] ChildHandle The handle of a child device of the specified device. + + @retval SHELL_NOT_FOUND A specified handle could not be found. + @retval SHELL_INVALID_PARAMETER A parameter has a invalid value. +**/ +SHELL_STATUS +PreHiiDrvCfg ( + IN CONST CHAR8 *Language, + IN BOOLEAN ForceDefaults, + IN UINT32 DefaultType, + IN BOOLEAN AllChildren, + IN BOOLEAN ValidateOptions, + IN BOOLEAN SetOptions, + IN EFI_HANDLE DriverImageHandle, + IN EFI_HANDLE DeviceHandle, + IN EFI_HANDLE ChildHandle + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + UINTN OuterLoopCounter; + CHAR8 *BestLanguage; + UINTN DriverImageHandleCount; + EFI_HANDLE *DriverImageHandleBuffer; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN *HandleType; + UINTN LoopCounter; + UINTN ChildIndex; + UINTN ChildHandleCount; + EFI_HANDLE *ChildHandleBuffer; + UINTN *ChildHandleType; + EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED ActionRequired; + EFI_DRIVER_CONFIGURATION_PROTOCOL *DriverConfiguration; + BOOLEAN Iso639Language; + UINTN HandleIndex1; + UINTN HandleIndex2; + UINTN HandleIndex3; + + ShellStatus = SHELL_SUCCESS; + + if (ChildHandle == NULL && AllChildren) { + SetOptions = FALSE; + } + + if (ForceDefaults) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRVCFG_FORCE_D), + gShellDriver1HiiHandle, + DefaultType); + } else if (ValidateOptions) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRVCFG_VALIDATE), + gShellDriver1HiiHandle); + } else if (SetOptions) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRVCFG_SET), + gShellDriver1HiiHandle); + } + + if (DriverImageHandle == 0) { + DriverImageHandleBuffer = GetHandleListByProtocolList(CfgGuidList); + if (DriverImageHandleBuffer == NULL) { + ShellStatus = SHELL_NOT_FOUND; + goto Done; + } + for ( + HandleBuffer = DriverImageHandleBuffer, DriverImageHandleCount = 0 + ; HandleBuffer != NULL && *HandleBuffer != NULL + ; HandleBuffer++,DriverImageHandleCount++); + } else { + DriverImageHandleCount = 1; + // + // Allocate buffer to hold the image handle so as to + // keep consistent with the above clause + // + DriverImageHandleBuffer = AllocatePool (sizeof (EFI_HANDLE)); + ASSERT (DriverImageHandleBuffer); + DriverImageHandleBuffer[0] = DriverImageHandle; + } + + for (OuterLoopCounter = 0; OuterLoopCounter < DriverImageHandleCount; OuterLoopCounter++) { + Iso639Language = FALSE; + Status = gBS->OpenProtocol ( + DriverImageHandleBuffer[OuterLoopCounter], + &gEfiDriverConfiguration2ProtocolGuid, + (VOID **) &DriverConfiguration, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + Iso639Language = TRUE; + Status = gBS->OpenProtocol ( + DriverImageHandleBuffer[OuterLoopCounter], + &gEfiDriverConfigurationProtocolGuid, + (VOID **) &DriverConfiguration, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + } + if (EFI_ERROR (Status)) { +// ShellPrintHiiEx( +// -1, +// -1, +// NULL, +// STRING_TOKEN (STR_DRVCFG_NOT_SUPPORT), +// gShellDriver1HiiHandle, +// ConvertHandleToHandleIndex (DriverImageHandleBuffer[OuterLoopCounter]) +// ); + ShellStatus = SHELL_UNSUPPORTED; + continue; + } + + BestLanguage = GetBestLanguage ( + DriverConfiguration->SupportedLanguages, + Iso639Language, + Language!=NULL?Language:"", + DriverConfiguration->SupportedLanguages, + NULL + ); + if (BestLanguage == NULL) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_GEN_NO_VALUE), + gShellDriver1HiiHandle, + L"drvcfg", + L"-l" + ); + ShellStatus = SHELL_INVALID_PARAMETER; + continue; + } + + Status = ParseHandleDatabaseByRelationshipWithType ( + DriverImageHandleBuffer[OuterLoopCounter], + NULL, + &HandleCount, + &HandleBuffer, + &HandleType + ); + if (EFI_ERROR (Status)) { + continue; + } + + if (SetOptions && DeviceHandle == NULL) { + + gST->ConOut->ClearScreen (gST->ConOut); + Status = DriverConfiguration->SetOptions ( + DriverConfiguration, + NULL, + NULL, + BestLanguage, + &ActionRequired + ); + gST->ConOut->ClearScreen (gST->ConOut); + + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRVCFG_ALL_LANG), + gShellDriver1HiiHandle, + ConvertHandleToHandleIndex (DriverImageHandleBuffer[OuterLoopCounter]), + DriverConfiguration->SupportedLanguages + ); + if (!EFI_ERROR (Status)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRVCFG_OPTIONS_SET), + gShellDriver1HiiHandle); + for (LoopCounter = 0; LoopCounter < HandleCount; LoopCounter++) { + if ((HandleType[LoopCounter] & HR_CONTROLLER_HANDLE) == HR_CONTROLLER_HANDLE) { + ShellCmdDriverConfigurationProcessActionRequired ( + DriverImageHandleBuffer[OuterLoopCounter], + HandleBuffer[LoopCounter], + NULL, + ActionRequired + ); + } + } + } else { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRVCFG_NOT_SET), + gShellDriver1HiiHandle, + Status); + } + continue; + } + + for (LoopCounter = 0; LoopCounter < HandleCount; LoopCounter++) { + if ((HandleType[LoopCounter] & HR_CONTROLLER_HANDLE) != HR_CONTROLLER_HANDLE) { + continue; + } + if (DeviceHandle != NULL && DeviceHandle != HandleBuffer[LoopCounter]) { + continue; + } + if (ChildHandle == NULL) { + HandleIndex1 = ConvertHandleToHandleIndex (DriverImageHandleBuffer[OuterLoopCounter]); + HandleIndex2 = ConvertHandleToHandleIndex (HandleBuffer[LoopCounter]); + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRVCFG_CTRL_LANG), + gShellDriver1HiiHandle, + HandleIndex1, + HandleIndex2, + DriverConfiguration->SupportedLanguages + ); + + if (ForceDefaults) { + Status = DriverConfiguration->ForceDefaults ( + DriverConfiguration, + HandleBuffer[LoopCounter], + NULL, + DefaultType, + &ActionRequired + ); + + if (!EFI_ERROR (Status)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRVCFG_DEF_FORCED), + gShellDriver1HiiHandle); + ShellCmdDriverConfigurationProcessActionRequired ( + DriverImageHandleBuffer[OuterLoopCounter], + HandleBuffer[LoopCounter], + NULL, + ActionRequired + ); + } else { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRVCFG_FORCE_FAILED), + gShellDriver1HiiHandle, + Status); + ShellStatus = SHELL_DEVICE_ERROR; + } + } else if (ValidateOptions) { + Status = DriverConfiguration->OptionsValid ( + DriverConfiguration, + HandleBuffer[LoopCounter], + NULL + ); + + if (!EFI_ERROR (Status)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRVCFG_OPTIONS_VALID), + gShellDriver1HiiHandle); + } else { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRVCFG_OPTIONS_INV), + gShellDriver1HiiHandle, + Status); + ShellStatus = SHELL_DEVICE_ERROR; + } + } else if (SetOptions) { + gST->ConOut->ClearScreen (gST->ConOut); + Status = DriverConfiguration->SetOptions ( + DriverConfiguration, + HandleBuffer[LoopCounter], + NULL, + BestLanguage, + &ActionRequired + ); + gST->ConOut->ClearScreen (gST->ConOut); + HandleIndex1 = ConvertHandleToHandleIndex (DriverImageHandleBuffer[OuterLoopCounter]); + HandleIndex2 = ConvertHandleToHandleIndex (HandleBuffer[LoopCounter]); + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRVCFG_CTRL_LANG), + gShellDriver1HiiHandle, + HandleIndex1, + HandleIndex2, + DriverConfiguration->SupportedLanguages + ); + if (!EFI_ERROR (Status)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRVCFG_OPTIONS_SET), + gShellDriver1HiiHandle); + + ShellCmdDriverConfigurationProcessActionRequired ( + DriverImageHandleBuffer[OuterLoopCounter], + HandleBuffer[LoopCounter], + NULL, + ActionRequired + ); + + } else { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRVCFG_NOT_SET), + gShellDriver1HiiHandle, + Status); + ShellStatus = SHELL_DEVICE_ERROR; + } + } else { + Print (L"\n"); + } + } + + if (ChildHandle == NULL && !AllChildren) { + continue; + } + + Status = ParseHandleDatabaseByRelationshipWithType ( + DriverImageHandleBuffer[OuterLoopCounter], + HandleBuffer[LoopCounter], + &ChildHandleCount, + &ChildHandleBuffer, + &ChildHandleType + ); + if (EFI_ERROR (Status)) { + continue; + } + + for (ChildIndex = 0; ChildIndex < ChildHandleCount; ChildIndex++) { + + if ((ChildHandleType[ChildIndex] & HR_CHILD_HANDLE) != HR_CHILD_HANDLE) { + continue; + } + + if (ChildHandle != NULL && ChildHandle != ChildHandleBuffer[ChildIndex]) { + continue; + } + + HandleIndex1 = ConvertHandleToHandleIndex (DriverImageHandleBuffer[OuterLoopCounter]); + HandleIndex2 = ConvertHandleToHandleIndex (HandleBuffer[LoopCounter]); + HandleIndex3 = ConvertHandleToHandleIndex (ChildHandleBuffer[ChildIndex]); + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRVCFG_CHILD_LANG), + gShellDriver1HiiHandle, + HandleIndex1, + HandleIndex2, + HandleIndex3, + DriverConfiguration->SupportedLanguages); + + if (ForceDefaults) { + Status = DriverConfiguration->ForceDefaults ( + DriverConfiguration, + HandleBuffer[LoopCounter], + ChildHandleBuffer[ChildIndex], + DefaultType, + &ActionRequired + ); + + if (!EFI_ERROR (Status)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRVCFG_DEF_FORCED), + gShellDriver1HiiHandle); + + ShellCmdDriverConfigurationProcessActionRequired ( + DriverImageHandleBuffer[OuterLoopCounter], + HandleBuffer[LoopCounter], + ChildHandleBuffer[ChildIndex], + ActionRequired + ); + + } else { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRVCFG_FORCE_FAILED), + gShellDriver1HiiHandle, + Status); + ShellStatus = SHELL_DEVICE_ERROR; + } + } else if (ValidateOptions) { + Status = DriverConfiguration->OptionsValid ( + DriverConfiguration, + HandleBuffer[LoopCounter], + ChildHandleBuffer[ChildIndex] + ); + + if (!EFI_ERROR (Status)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRVCFG_OPTIONS_VALID), + gShellDriver1HiiHandle); + } else { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRVCFG_OPTIONS_INV), + gShellDriver1HiiHandle, + Status); + ShellStatus = SHELL_DEVICE_ERROR; + } + } else if (SetOptions) { + gST->ConOut->ClearScreen (gST->ConOut); + Status = DriverConfiguration->SetOptions ( + DriverConfiguration, + HandleBuffer[LoopCounter], + ChildHandleBuffer[ChildIndex], + BestLanguage, + &ActionRequired + ); + gST->ConOut->ClearScreen (gST->ConOut); + HandleIndex1 = ConvertHandleToHandleIndex (DriverImageHandleBuffer[OuterLoopCounter]); + HandleIndex2 = ConvertHandleToHandleIndex (HandleBuffer[LoopCounter]); + HandleIndex3 = ConvertHandleToHandleIndex (ChildHandleBuffer[ChildIndex]); + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRVCFG_CHILD_LANG), + gShellDriver1HiiHandle, + HandleIndex1, + HandleIndex2, + HandleIndex3, + DriverConfiguration->SupportedLanguages + ); + if (!EFI_ERROR (Status)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRVCFG_OPTIONS_SET), + gShellDriver1HiiHandle); + + ShellCmdDriverConfigurationProcessActionRequired ( + DriverImageHandleBuffer[OuterLoopCounter], + HandleBuffer[LoopCounter], + ChildHandleBuffer[ChildIndex], + ActionRequired + ); + + } else { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRVCFG_NOT_SET), + gShellDriver1HiiHandle, + Status); + ShellStatus = SHELL_DEVICE_ERROR; + } + } else { + Print (L"\n"); + } + } + + FreePool (ChildHandleBuffer); + FreePool (ChildHandleType); + } + + FreePool (BestLanguage); + FreePool (HandleBuffer); + FreePool (HandleType); + } + + if (DriverImageHandle != NULL && DriverImageHandleCount != 0) { + FreePool (DriverImageHandleBuffer); + } + +Done: + return ShellStatus; +} + +/** + Function to print out configuration information on all configurable handles. + + @param[in] ChildrenToo TRUE to tewst for children. + @param[in] Language ASCII string for language code. + @param[in] UseHii TRUE to check for Hii and DPC, FALSE for DCP only. + + @retval SHELL_SUCCESS The operation was successful. +**/ +SHELL_STATUS +PrintConfigInfoOnAll( + IN CONST BOOLEAN ChildrenToo, + IN CONST CHAR8 *Language, + IN CONST BOOLEAN UseHii + ) +{ + EFI_HANDLE *HandleList; + EFI_HANDLE *CurrentHandle; + BOOLEAN Found; + UINTN Index2; + + + Found = FALSE; + HandleList = NULL; + CurrentHandle = NULL; + + if (UseHii) { + // + // HII method + // + HandleList = GetHandleListByProtocol(&gEfiHiiConfigAccessProtocolGuid); + for (CurrentHandle = HandleList ; CurrentHandle != NULL && *CurrentHandle != NULL; CurrentHandle++){ + Found = TRUE; + Index2 = *CurrentHandle == NULL ? 0 : ConvertHandleToHandleIndex(*CurrentHandle); + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRVCFG_LINE_HII), + gShellDriver1HiiHandle, + Index2 + ); + } + SHELL_FREE_NON_NULL(HandleList); + } + + if (PreHiiDrvCfg ( + Language, + FALSE, + 0, + ChildrenToo, + FALSE, + FALSE, + 0, + 0, + 0) == SHELL_SUCCESS) { + Found = TRUE; + } + + if (!Found) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_DRVCFG_NONE_FOUND), gShellDriver1HiiHandle); + return (SHELL_SUCCESS); + } + + return (SHELL_SUCCESS); +} + +STATIC CONST SHELL_PARAM_ITEM ParamListHii[] = { + {L"-s", TypeFlag}, + {L"-l", TypeValue}, + {L"-f", TypeValue}, + {L"-o", TypeValue}, + {L"-i", TypeValue}, + {NULL, TypeMax} + }; +STATIC CONST SHELL_PARAM_ITEM ParamListPreHii[] = { + {L"-c", TypeFlag}, + {L"-s", TypeFlag}, + {L"-v", TypeFlag}, + {L"-l", TypeValue}, + {L"-f", TypeValue}, + {NULL, TypeMax} + }; + +/** + Function for 'drvcfg' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunDrvCfg ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CHAR8 *Language; + CONST CHAR16 *Lang; + CONST CHAR16 *HandleIndex1; + CONST CHAR16 *HandleIndex2; + CONST CHAR16 *HandleIndex3; + CONST CHAR16 *ForceTypeString; + BOOLEAN Force; + BOOLEAN Set; + BOOLEAN Validate; + BOOLEAN InFromFile; + BOOLEAN OutToFile; + BOOLEAN AllChildren; + BOOLEAN UseHii; + UINT32 ForceType; + UINT64 Intermediate; + EFI_HANDLE Handle1; + EFI_HANDLE Handle2; + EFI_HANDLE Handle3; + CONST CHAR16 *FileName; + + ShellStatus = SHELL_SUCCESS; + Status = EFI_SUCCESS; + Language = NULL; + UseHii = TRUE; + ProblemParam = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamListHii, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status) || ShellCommandLineGetCount(Package) > 2) { + UseHii = FALSE; + if (Package != NULL) { + ShellCommandLineFreeVarList (Package); + } + SHELL_FREE_NON_NULL(ProblemParam); + Status = ShellCommandLineParse (ParamListPreHii, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDriver1HiiHandle, L"drvcfg", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } else { + ASSERT(FALSE); + } + } + } + if (ShellStatus == SHELL_SUCCESS) { + if (ShellCommandLineGetCount(Package) > 4) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDriver1HiiHandle, L"drvcfg"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + Lang = ShellCommandLineGetValue(Package, L"-l"); + if (Lang != NULL) { + Language = AllocateZeroPool(StrSize(Lang)); + AsciiSPrint(Language, StrSize(Lang), "%S", Lang); + } else if (ShellCommandLineGetFlag(Package, L"-l")){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDriver1HiiHandle, L"drvcfg", L"-l"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + Set = ShellCommandLineGetFlag (Package, L"-s"); + Validate = ShellCommandLineGetFlag (Package, L"-v"); + InFromFile = ShellCommandLineGetFlag (Package, L"-i"); + OutToFile = ShellCommandLineGetFlag (Package, L"-o"); + AllChildren = ShellCommandLineGetFlag (Package, L"-c"); + Force = ShellCommandLineGetFlag (Package, L"-f"); + ForceTypeString = ShellCommandLineGetValue(Package, L"-f"); + + if (OutToFile) { + FileName = ShellCommandLineGetValue(Package, L"-o"); + } else if (InFromFile) { + FileName = ShellCommandLineGetValue(Package, L"-i"); + } else { + FileName = NULL; + } + + if (InFromFile && EFI_ERROR(ShellFileExists(FileName))) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FIND_FAIL), gShellDriver1HiiHandle, L"drvcfg", FileName); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + if (OutToFile && !EFI_ERROR(ShellFileExists(FileName))) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_EXIST), gShellDriver1HiiHandle, L"drvcfg", FileName); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + if (Force && ForceTypeString == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDriver1HiiHandle, L"drvcfg", L"-f"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + if (Force) { + Status = ShellConvertStringToUint64(ForceTypeString, &Intermediate, FALSE, FALSE); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellDriver1HiiHandle, L"drvcfg", ForceTypeString, L"-f"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + ForceType = (UINT32)Intermediate; + } else { + ForceType = 0; + } + HandleIndex1 = ShellCommandLineGetRawValue(Package, 1); + Handle1 = NULL; + if (HandleIndex1 != NULL && !EFI_ERROR(ShellConvertStringToUint64(HandleIndex1, &Intermediate, TRUE, FALSE))) { + Handle1 = ConvertHandleIndexToHandle((UINTN)Intermediate); + if (Handle1 == NULL || (UINT64)(UINTN)Intermediate != Intermediate) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"drvcfg", HandleIndex1); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + } + HandleIndex2 = ShellCommandLineGetRawValue(Package, 2); + Handle2 = NULL; + if (HandleIndex2 != NULL && !EFI_ERROR(ShellConvertStringToUint64(HandleIndex2, &Intermediate, TRUE, FALSE))) { + Handle2 = ConvertHandleIndexToHandle((UINTN)Intermediate); + if (Handle2 == NULL || (UINT64)(UINTN)Intermediate != Intermediate) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"drvcfg", HandleIndex2); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + } + HandleIndex3 = ShellCommandLineGetRawValue(Package, 3); + Handle3 = NULL; + if (HandleIndex3 != NULL && !EFI_ERROR(ShellConvertStringToUint64(HandleIndex3, &Intermediate, TRUE, FALSE))) { + Handle3 = ConvertHandleIndexToHandle((UINTN)Intermediate); + if (Handle3 == NULL || (UINT64)(UINTN)Intermediate != Intermediate) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"drvcfg", HandleIndex3); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + } + + if ((InFromFile || OutToFile) && (FileName == NULL)) { + if (FileName == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDriver1HiiHandle, L"drvcfg", InFromFile?L"-i":L"-o"); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_HANDLE_REQ), gShellDriver1HiiHandle, L"drvcfg"); + } + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + if (!UseHii && (InFromFile || OutToFile)) { + if (InFromFile) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDriver1HiiHandle, L"drvcfg", L"-i"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + if (OutToFile) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDriver1HiiHandle, L"drvcfg", L"-o"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + } + if (Validate && Force) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CONFLICT), gShellDriver1HiiHandle, L"drvcfg", L"-v", L"-f"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + if (Validate && Set) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CONFLICT), gShellDriver1HiiHandle, L"drvcfg", L"-v", L"-s"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + if (Set && Force) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CONFLICT), gShellDriver1HiiHandle, L"drvcfg", L"-s", L"-f"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + if (OutToFile && InFromFile) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CONFLICT), gShellDriver1HiiHandle, L"drvcfg", L"-i", L"-o"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + + // + // We do HII first. + // + if (UseHii) { + if (Handle1 != NULL && EFI_ERROR(gBS->OpenProtocol(Handle1, &gEfiHiiConfigAccessProtocolGuid, NULL, gImageHandle, NULL, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) { + // + // no HII on this handle. + // + ShellStatus = SHELL_UNSUPPORTED; + } else if (Validate) { + } else if (Force) { + } else if (Set) { + } else if (InFromFile) { + ShellStatus = ConfigFromFile(Handle1, FileName); + if (Handle1 != NULL && ShellStatus == SHELL_SUCCESS) { + goto Done; + } + } else if (OutToFile) { + ShellStatus = ConfigToFile(Handle1, FileName); + if (Handle1 != NULL && ShellStatus == SHELL_SUCCESS) { + goto Done; + } + } else if (HandleIndex1 == NULL) { + // + // display all that are configurable + // + ShellStatus = PrintConfigInfoOnAll(AllChildren, Language, UseHii); + goto Done; + } else { + if (!EFI_ERROR(gBS->OpenProtocol(Handle1, &gEfiHiiConfigAccessProtocolGuid, NULL, gImageHandle, NULL, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRVCFG_LINE_HII), + gShellDriver1HiiHandle, + ConvertHandleToHandleIndex(Handle1) + ); + goto Done; + } + } + } + + // + // We allways need to do this one since it does both by default. + // + if (!InFromFile && !OutToFile) { + ShellStatus = PreHiiDrvCfg ( + Language, + Force, + ForceType, + AllChildren, + Validate, + Set, + Handle1, + Handle2, + Handle3); + } + + if (ShellStatus == SHELL_UNSUPPORTED) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRVCFG_NOT_SUPPORT), + gShellDriver1HiiHandle, + ConvertHandleToHandleIndex(Handle1) + ); + } + } + +Done: + ShellCommandLineFreeVarList (Package); + SHELL_FREE_NON_NULL(Language); + return (ShellStatus); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/DrvDiag.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/DrvDiag.c new file mode 100644 index 00000000..8db442bf --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/DrvDiag.c @@ -0,0 +1,457 @@ +/** @file + Main file for DrvDiag shell Driver1 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDriver1CommandsLib.h" + +STATIC CONST EFI_GUID *DiagGuidList[] = {&gEfiDriverDiagnosticsProtocolGuid, &gEfiDriverDiagnostics2ProtocolGuid, NULL}; +// +// We need 1 more item on the list... +// +typedef enum { + TestModeStandard = EfiDriverDiagnosticTypeStandard, + TestModeExtended = EfiDriverDiagnosticTypeExtended, + TestModeManufacturing = EfiDriverDiagnosticTypeManufacturing, + TestModeList, + TestModeMax +} DRV_DIAG_TEST_MODE; + +/** + Do the diagnostics call for some set of handles. + + @param[in] Mode The type of diagnostic test to run. + @param[in] Lang The language code to use. + @param[in] AllChilds Should the test be on all children. + @param[in] DriverHandle The driver handle to test with. + @param[in] ControllerHandle The specific controller handle to test. + @param[in] ChildHandle The specific child handle to test. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_INVALID_PARAMETER A parameter had an invalid value. + @retval EFI_NOT_FOUND No diagnostic handle could be found. +**/ +EFI_STATUS +DoDiagnostics ( + IN CONST DRV_DIAG_TEST_MODE Mode, + IN CONST CHAR8 *Lang, + IN CONST BOOLEAN AllChilds, + IN CONST EFI_HANDLE DriverHandle, + IN CONST EFI_HANDLE ControllerHandle, + IN CONST EFI_HANDLE ChildHandle + ) +{ + EFI_DRIVER_DIAGNOSTICS_PROTOCOL *DriverDiagnostics; + EFI_DRIVER_DIAGNOSTICS2_PROTOCOL *DriverDiagnostics2; + EFI_HANDLE *DriverHandleList; + EFI_HANDLE *ControllerHandleList; + EFI_HANDLE *ChildHandleList; + EFI_HANDLE *Walker; + UINTN DriverHandleListCount; + UINTN ControllerHandleListCount; + UINTN ChildHandleListCount; + UINTN DriverHandleListLoop; + UINTN ControllerHandleListLoop; + UINTN ChildHandleListLoop; + EFI_STATUS Status; + EFI_STATUS Status2; + EFI_GUID *ErrorType; + UINTN OutBufferSize; + CHAR16 *OutBuffer; + UINTN HandleIndex1; + UINTN HandleIndex2; + CHAR8 *Language; + BOOLEAN Found; + + if ((ChildHandle != NULL && AllChilds) || (Mode >= TestModeMax)){ + return (EFI_INVALID_PARAMETER); + } + + DriverDiagnostics = NULL; + DriverDiagnostics2 = NULL; + Status = EFI_SUCCESS; + Status2 = EFI_SUCCESS; + DriverHandleList = NULL; + ControllerHandleList = NULL; + ChildHandleList = NULL; + Language = NULL; + OutBuffer = NULL; + ErrorType = NULL; + DriverHandleListCount = 0; + ControllerHandleListCount = 0; + ChildHandleListCount = 0; + + if (DriverHandle != NULL) { + DriverHandleList = AllocateZeroPool(2*sizeof(EFI_HANDLE)); + if (DriverHandleList == NULL) { + return EFI_OUT_OF_RESOURCES; + } + DriverHandleList[0] = DriverHandle; + DriverHandleListCount = 1; + } else { + DriverHandleList = GetHandleListByProtocolList(DiagGuidList); + if (DriverHandleList == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROTOCOL_NF), gShellDriver1HiiHandle, L"drvdiag", L"gEfiDriverDiagnosticsProtocolGuid", &gEfiDriverDiagnosticsProtocolGuid); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROTOCOL_NF), gShellDriver1HiiHandle, L"drvdiag", L"gEfiDriverDiagnostics2ProtocolGuid", &gEfiDriverDiagnostics2ProtocolGuid); + return (EFI_NOT_FOUND); + } + for (Walker = DriverHandleList ; Walker != NULL && *Walker != NULL ; DriverHandleListCount++, Walker++); + } + + if (ControllerHandle != NULL) { + ControllerHandleList = AllocateZeroPool(2*sizeof(EFI_HANDLE)); + if (ControllerHandleList == NULL) { + SHELL_FREE_NON_NULL (DriverHandleList); + return EFI_OUT_OF_RESOURCES; + } + ControllerHandleList[0] = ControllerHandle; + ControllerHandleListCount = 1; + } else { + ControllerHandleList = NULL; + } + + if (ChildHandle != NULL) { + ChildHandleList = AllocateZeroPool(2*sizeof(EFI_HANDLE)); + if (ChildHandleList == NULL) { + SHELL_FREE_NON_NULL (ControllerHandleList); + SHELL_FREE_NON_NULL (DriverHandleList); + return EFI_OUT_OF_RESOURCES; + } + ChildHandleList[0] = ChildHandle; + ChildHandleListCount = 1; + } else if (AllChilds) { + ChildHandleList = NULL; + // + // This gets handled in the loop below. + // + } else { + ChildHandleList = NULL; + } + + if (Mode == TestModeList) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_DRVDIAG_HEADER), gShellDriver1HiiHandle); + } + for (DriverHandleListLoop = 0 + ; DriverHandleListLoop < DriverHandleListCount + ; DriverHandleListLoop++ + ){ + if (Mode == TestModeList) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_DRVDIAG_DRIVER_HEADER), gShellDriver1HiiHandle, ConvertHandleToHandleIndex(DriverHandleList[DriverHandleListLoop])); + } + if (ControllerHandle == NULL) { + PARSE_HANDLE_DATABASE_DEVICES(DriverHandleList[DriverHandleListLoop], &ControllerHandleListCount, &ControllerHandleList); + } + if (ControllerHandleListCount == 0) { + if (Mode == TestModeList) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_DRVDIAG_DRIVER_NO_HANDLES), gShellDriver1HiiHandle); + } + } else { + if (Mode == TestModeList) { + ShellPrintEx(-1, -1, L"\r\n"); + } + for (ControllerHandleListLoop = 0 + ; ControllerHandleListLoop < ControllerHandleListCount + ; ControllerHandleListLoop++ + ){ + if (AllChilds) { + ASSERT(ChildHandleList == NULL); + PARSE_HANDLE_DATABASE_MANAGED_CHILDREN( + DriverHandleList[DriverHandleListLoop], + ControllerHandleList[ControllerHandleListLoop], + &ChildHandleListCount, + &ChildHandleList); + } + for (ChildHandleListLoop = 0 + ; (ChildHandleListLoop < ChildHandleListCount || ChildHandleList == NULL) + ; ChildHandleListLoop++ + ){ + Found = FALSE; + if (Mode != TestModeList) { + if (Lang == NULL || Lang[2] == '-') { + // + // Get the protocol pointer and call the function + // + Status = gBS->OpenProtocol( + DriverHandleList[DriverHandleListLoop], + &gEfiDriverDiagnostics2ProtocolGuid, + (VOID**)&DriverDiagnostics2, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (!EFI_ERROR(Status) && (DriverDiagnostics2 != NULL)) { + Language = GetBestLanguageForDriver(DriverDiagnostics2->SupportedLanguages, Lang, FALSE); + Found = TRUE; + Status = DriverDiagnostics2->RunDiagnostics( + DriverDiagnostics2, + ControllerHandleList[ControllerHandleListLoop], + ChildHandleList == NULL?NULL:ChildHandleList[ChildHandleListLoop], + (EFI_DRIVER_DIAGNOSTIC_TYPE)Mode, + Language, + &ErrorType, + &OutBufferSize, + &OutBuffer); + FreePool(Language); + } + } + if (!Found && (Lang == NULL||(Lang!=NULL&&(Lang[2]!='-')))){ + Status = gBS->OpenProtocol( + DriverHandleList[DriverHandleListLoop], + &gEfiDriverDiagnosticsProtocolGuid, + (VOID**)&DriverDiagnostics, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (!EFI_ERROR(Status)) { + Language = GetBestLanguageForDriver(DriverDiagnostics->SupportedLanguages, Lang, FALSE); + Status = DriverDiagnostics->RunDiagnostics( + DriverDiagnostics, + ControllerHandleList[ControllerHandleListLoop], + ChildHandleList == NULL?NULL:ChildHandleList[ChildHandleListLoop], + (EFI_DRIVER_DIAGNOSTIC_TYPE)Mode, + Language, + &ErrorType, + &OutBufferSize, + &OutBuffer); + FreePool(Language); + } + } + if (EFI_ERROR(Status)) { + Status2 = Status; + } + HandleIndex1 = ConvertHandleToHandleIndex(DriverHandleList[DriverHandleListLoop]); + HandleIndex2 = ConvertHandleToHandleIndex(ControllerHandleList[ControllerHandleListLoop]); + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_3P_RESULT), + gShellDriver1HiiHandle, + L"DrvDiag", + HandleIndex1, + HandleIndex2, + ChildHandleList == NULL?0:ConvertHandleToHandleIndex(ChildHandleList[ChildHandleListLoop]), + Status); + if (OutBuffer!=NULL) { + FreePool(OutBuffer); + OutBuffer = NULL; + } + if (ErrorType!=NULL) { + FreePool(ErrorType); + ErrorType = NULL; + } + } else { + HandleIndex1 = ConvertHandleToHandleIndex(DriverHandleList[DriverHandleListLoop]); + HandleIndex2 = ConvertHandleToHandleIndex(ControllerHandleList[ControllerHandleListLoop]); + // + // Print out the information that this set can be tested + // + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_DRV_DIAG_ITEM_LINE), + gShellDriver1HiiHandle, + HandleIndex1, + HandleIndex2, + ChildHandleList == NULL?0:ConvertHandleToHandleIndex(ChildHandleList[ChildHandleListLoop]) + ); + } + + // + // If we are doing a single pass with NULL child jump out after a single loop + // + if (ChildHandleList == NULL) { + break; + } + } + if (AllChilds) { + SHELL_FREE_NON_NULL(ChildHandleList); + ChildHandleList = NULL; + ChildHandleListCount = 0; + } + } + if (ControllerHandle == NULL) { + SHELL_FREE_NON_NULL(ControllerHandleList); + ControllerHandleList = NULL; + ControllerHandleListCount = 0; + } + } + } + + if (DriverHandleList != NULL) { + FreePool(DriverHandleList); + } + if (ControllerHandleList != NULL) { + FreePool(ControllerHandleList); + } + if (ChildHandleList != NULL) { + FreePool(ChildHandleList); + } + return (Status2); +} + + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-c", TypeFlag}, + {L"-s", TypeFlag}, + {L"-e", TypeFlag}, + {L"-m", TypeFlag}, + {L"-l", TypeValue}, + {NULL, TypeMax} + }; + +/** + Function for 'drvdiag' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunDrvDiag ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + DRV_DIAG_TEST_MODE Mode; + CHAR8 *Language; + CONST CHAR16 *DriverHandleStr; + CONST CHAR16 *ControllerHandleStr; + CONST CHAR16 *ChildHandleStr; + CONST CHAR16 *Lang; + EFI_HANDLE Handle1; + EFI_HANDLE Handle2; + EFI_HANDLE Handle3; + UINT64 Intermediate; + + ShellStatus = SHELL_SUCCESS; + Mode = TestModeMax; + Language = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDriver1HiiHandle, L"drvdiag", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // if more than 3 'value' parameters (plus the name one) or we have any 2 mode flags + // + if ((ShellCommandLineGetCount(Package) > 4) + ||(ShellCommandLineGetFlag(Package, L"-s") && ShellCommandLineGetFlag(Package, L"-e")) + ||(ShellCommandLineGetFlag(Package, L"-s") && ShellCommandLineGetFlag(Package, L"-m")) + ||(ShellCommandLineGetFlag(Package, L"-e") && ShellCommandLineGetFlag(Package, L"-m")) + ){ + // + // error for too many parameters + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDriver1HiiHandle, L"drvdiag"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if ((ShellCommandLineGetFlag(Package, L"-s")) + || (ShellCommandLineGetFlag(Package, L"-e")) + || (ShellCommandLineGetFlag(Package, L"-m")) + ){ + // + // Run the appropriate test + // + if (ShellCommandLineGetFlag(Package, L"-s")) { + Mode = TestModeStandard; + } else if (ShellCommandLineGetFlag(Package, L"-e")) { + Mode = TestModeExtended; + } else if (ShellCommandLineGetFlag(Package, L"-m")) { + Mode = TestModeManufacturing; + } else { + ASSERT(FALSE); + } + } else { + // + // Do a listing of what's available to test + // + Mode = TestModeList; + } + + Lang = ShellCommandLineGetValue(Package, L"-l"); + if (ShellCommandLineGetFlag(Package, L"-l") && Lang == NULL) { + ASSERT(Language == NULL); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDriver1HiiHandle, L"drvdiag", L"-l"); + ShellCommandLineFreeVarList (Package); + return (SHELL_INVALID_PARAMETER); + } else if (Lang != NULL) { + Language = AllocateZeroPool(StrSize(Lang)); + AsciiSPrint(Language, StrSize(Lang), "%S", Lang); + } + + DriverHandleStr = ShellCommandLineGetRawValue(Package, 1); + ControllerHandleStr = ShellCommandLineGetRawValue(Package, 2); + ChildHandleStr = ShellCommandLineGetRawValue(Package, 3); + + if (DriverHandleStr == NULL) { + Handle1 = NULL; + } else { + ShellConvertStringToUint64(DriverHandleStr, &Intermediate, TRUE, FALSE); + Handle1 = ConvertHandleIndexToHandle((UINTN)Intermediate); + } + if (ControllerHandleStr == NULL) { + Handle2 = NULL; + } else { + ShellConvertStringToUint64(ControllerHandleStr, &Intermediate, TRUE, FALSE); + Handle2 = ConvertHandleIndexToHandle((UINTN)Intermediate); + } + if (ChildHandleStr == NULL) { + Handle3 = NULL; + } else { + ShellConvertStringToUint64(ChildHandleStr, &Intermediate, TRUE, FALSE); + Handle3 = ConvertHandleIndexToHandle((UINTN)Intermediate); + } + + Status = DoDiagnostics ( + Mode, + Language, + ShellCommandLineGetFlag(Package, L"-c"), + Handle1, + Handle2, + Handle3 + ); + + SHELL_FREE_NON_NULL(Language); + ShellCommandLineFreeVarList (Package); + + } + if (ShellStatus == SHELL_SUCCESS) { + if (Status == EFI_SECURITY_VIOLATION) { + ShellStatus = SHELL_SECURITY_VIOLATION; + } else if (Status == EFI_INVALID_PARAMETER) { + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (Status == EFI_NOT_FOUND) { + ShellStatus = SHELL_NOT_FOUND; + } else if (EFI_ERROR(Status)) { + ShellStatus = SHELL_NOT_FOUND; + } + } + + return (ShellStatus); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/OpenInfo.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/OpenInfo.c new file mode 100644 index 00000000..e84f426b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/OpenInfo.c @@ -0,0 +1,210 @@ +/** @file + Main file for OpenInfo shell Driver1 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDriver1CommandsLib.h" + +STATIC CONST CHAR16 StringHandProt[] = L"HandProt "; +STATIC CONST CHAR16 StringGetProt[] = L"GetProt "; +STATIC CONST CHAR16 StringTestProt[] = L"TestProt "; +STATIC CONST CHAR16 StringChild[] = L"Child "; +STATIC CONST CHAR16 StringDriver[] = L"Driver "; +STATIC CONST CHAR16 StringExclusive[] = L"Exclusive"; +STATIC CONST CHAR16 StringDriverEx[] = L"DriverEx "; +STATIC CONST CHAR16 StringUnknown[] = L"Unknown "; + +/** + Open the database and print out all the info about TheHandle. + + @param[in] TheHandle The handle to print info on. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_INVALID_PARAMETER TheHandle was NULL. +**/ +EFI_STATUS +TraverseHandleDatabase ( + IN CONST EFI_HANDLE TheHandle + ) +{ + EFI_STATUS Status; + EFI_GUID **ProtocolGuidArray; + UINTN ArrayCount; + UINTN ProtocolIndex; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo; + UINTN OpenInfoCount; + UINTN OpenInfoIndex; + CONST CHAR16 *OpenTypeString; + CHAR16 *TempString; + UINTN HandleIndex; + CONST CHAR16 *Name; + UINTN ControllerIndex; + + if (TheHandle == NULL) { + return (EFI_INVALID_PARAMETER); + } + + // + // Retrieve the list of all the protocols on the handle + // + Status = gBS->ProtocolsPerHandle ( + TheHandle, + &ProtocolGuidArray, + &ArrayCount + ); + ASSERT_EFI_ERROR(Status); + if (!EFI_ERROR (Status)) { + + for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) { + // + // print out the human readable name for this one. + // + TempString = GetStringNameFromGuid(ProtocolGuidArray[ProtocolIndex], NULL); + if (TempString == NULL) { + continue; + } + ShellPrintEx(-1, -1, L"%H%s%N\r\n", TempString); + FreePool(TempString); + + // + // Retrieve the list of agents that have opened each protocol + // + Status = gBS->OpenProtocolInformation ( + TheHandle, + ProtocolGuidArray[ProtocolIndex], + &OpenInfo, + &OpenInfoCount + ); + ASSERT_EFI_ERROR(Status); + if (!EFI_ERROR (Status)) { + for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) { + switch (OpenInfo[OpenInfoIndex].Attributes) { + case EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL: OpenTypeString = StringHandProt; break; + case EFI_OPEN_PROTOCOL_GET_PROTOCOL: OpenTypeString = StringGetProt; break; + case EFI_OPEN_PROTOCOL_TEST_PROTOCOL: OpenTypeString = StringTestProt; break; + case EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER: OpenTypeString = StringChild; break; + case EFI_OPEN_PROTOCOL_BY_DRIVER: OpenTypeString = StringDriver; break; + case EFI_OPEN_PROTOCOL_EXCLUSIVE: OpenTypeString = StringExclusive; break; + case EFI_OPEN_PROTOCOL_BY_DRIVER|EFI_OPEN_PROTOCOL_EXCLUSIVE: + OpenTypeString = StringDriverEx; break; + default: OpenTypeString = StringUnknown; break; + } + HandleIndex = ConvertHandleToHandleIndex(OpenInfo[OpenInfoIndex].AgentHandle); + Name = GetStringNameFromHandle(OpenInfo[OpenInfoIndex].AgentHandle, NULL); + ControllerIndex = ConvertHandleToHandleIndex(OpenInfo[OpenInfoIndex].ControllerHandle); + if (ControllerIndex != 0) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN(STR_OPENINFO_LINE), + gShellDriver1HiiHandle, + HandleIndex, + ControllerIndex, + OpenInfo[OpenInfoIndex].OpenCount, + OpenTypeString, + Name + ); + } else { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN(STR_OPENINFO_MIN_LINE), + gShellDriver1HiiHandle, + HandleIndex, + OpenInfo[OpenInfoIndex].OpenCount, + OpenTypeString, + Name + ); + } + } + FreePool (OpenInfo); + } + } + FreePool (ProtocolGuidArray); + } + + return Status; +} + +/** + Function for 'openinfo' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunOpenInfo ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + EFI_HANDLE TheHandle; + CONST CHAR16 *Param1; + UINT64 Intermediate; + + ShellStatus = SHELL_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDriver1HiiHandle, L"openinfo", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetCount(Package) > 2){ + // + // error for too many parameters + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDriver1HiiHandle, L"openinfo"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetCount(Package) == 0) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDriver1HiiHandle, L"openinfo"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Param1 = ShellCommandLineGetRawValue(Package, 1); + Status = ShellConvertStringToUint64(Param1, &Intermediate, TRUE, FALSE); + if (EFI_ERROR(Status) || Param1 == NULL || ConvertHandleIndexToHandle((UINTN)Intermediate) == NULL){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"openinfo", Param1); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + TheHandle = ConvertHandleIndexToHandle((UINTN)Intermediate); + ASSERT(TheHandle != NULL); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_OPENINFO_HEADER_LINE), gShellDriver1HiiHandle, (UINTN)Intermediate, TheHandle); + + Status = TraverseHandleDatabase (TheHandle); + if (!EFI_ERROR(Status)) { + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"openinfo", Param1); + ShellStatus = SHELL_NOT_FOUND; + } + } + } + } + return (ShellStatus); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Reconnect.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Reconnect.c new file mode 100644 index 00000000..8c3740a9 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Reconnect.c @@ -0,0 +1,93 @@ +/** @file + Main file for Reconnect shell Driver1 function. + + Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDriver1CommandsLib.h" + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-r", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Connect all the possible console devices. + +**/ +VOID +ConnectAllConsoles ( + VOID + ) +{ + ShellConnectFromDevPaths(L"ConInDev"); + ShellConnectFromDevPaths(L"ConOutDev"); + ShellConnectFromDevPaths(L"ErrOutDev"); + + ShellConnectFromDevPaths(L"ErrOut"); + ShellConnectFromDevPaths(L"ConIn"); + ShellConnectFromDevPaths(L"ConOut"); +} + + +/** + Function for 'reconnect' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunReconnect ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + SHELL_STATUS ShellStatus; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + EFI_STATUS Status; + + gInReconnect = TRUE; + ShellStatus = SHELL_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDriver1HiiHandle, L"reconnect", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + ShellStatus = ShellCommandRunDisconnect(ImageHandle, SystemTable); + if (ShellStatus == SHELL_SUCCESS) { + if (ShellCommandLineGetFlag(Package, L"-r")) { + ConnectAllConsoles(); + } + ShellStatus = ShellCommandRunConnect(ImageHandle, SystemTable); + } + } + + gInReconnect = FALSE; + + return (ShellStatus); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.c new file mode 100644 index 00000000..53033321 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.c @@ -0,0 +1,98 @@ +/** @file + Main file for NULL named library for level 1 shell command functions. + + Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDriver1CommandsLib.h" + +STATIC CONST CHAR16 mFileName[] = L"Driver1Commands"; +EFI_HII_HANDLE gShellDriver1HiiHandle = NULL; +BOOLEAN gInReconnect = FALSE; + +/** + Function to return the name of the file containing help if HII will not be used. + + @return The filename. +**/ +CONST CHAR16* +EFIAPI +ShellCommandGetManFileNameDriver1 ( + VOID + ) +{ + return (mFileName); +} + +/** + Constructor for the Shell Driver1 Commands library. + + @param ImageHandle the image handle of the process + @param SystemTable the EFI System Table pointer + + @retval EFI_SUCCESS the shell command handlers were installed sucessfully + @retval EFI_UNSUPPORTED the shell level required was not found. +**/ +EFI_STATUS +EFIAPI +UefiShellDriver1CommandsLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + // + // check our bit of the profiles mask + // + if ((PcdGet8(PcdShellProfileMask) & BIT0) == 0) { + return (EFI_SUCCESS); + } + + // + // install the HII stuff. + // + gShellDriver1HiiHandle = HiiAddPackages (&gShellDriver1HiiGuid, gImageHandle, UefiShellDriver1CommandsLibStrings, NULL); + if (gShellDriver1HiiHandle == NULL) { + return (EFI_DEVICE_ERROR); + } + + // + // install our shell command handlers that are always installed + // + ShellCommandRegisterCommandName(L"connect", ShellCommandRunConnect , ShellCommandGetManFileNameDriver1, 0, L"Driver1", TRUE, gShellDriver1HiiHandle, STRING_TOKEN(STR_GET_HELP_CONNECT) ); + ShellCommandRegisterCommandName(L"devices", ShellCommandRunDevices , ShellCommandGetManFileNameDriver1, 0, L"Driver1", TRUE, gShellDriver1HiiHandle, STRING_TOKEN(STR_GET_HELP_DEVICES) ); + ShellCommandRegisterCommandName(L"openinfo", ShellCommandRunOpenInfo , ShellCommandGetManFileNameDriver1, 0, L"Driver1", TRUE, gShellDriver1HiiHandle, STRING_TOKEN(STR_GET_HELP_OPENINFO) ); + ShellCommandRegisterCommandName(L"disconnect", ShellCommandRunDisconnect , ShellCommandGetManFileNameDriver1, 0, L"Driver1", TRUE, gShellDriver1HiiHandle, STRING_TOKEN(STR_GET_HELP_DISCONNECT)); + ShellCommandRegisterCommandName(L"reconnect", ShellCommandRunReconnect , ShellCommandGetManFileNameDriver1, 0, L"Driver1", TRUE, gShellDriver1HiiHandle, STRING_TOKEN(STR_GET_HELP_RECONNECT) ); + ShellCommandRegisterCommandName(L"unload", ShellCommandRunUnload , ShellCommandGetManFileNameDriver1, 0, L"Driver1", TRUE, gShellDriver1HiiHandle, STRING_TOKEN(STR_GET_HELP_UNLOAD) ); + ShellCommandRegisterCommandName(L"drvdiag", ShellCommandRunDrvDiag , ShellCommandGetManFileNameDriver1, 0, L"Driver1", TRUE, gShellDriver1HiiHandle, STRING_TOKEN(STR_GET_HELP_DRVDIAG) ); + ShellCommandRegisterCommandName(L"dh", ShellCommandRunDh , ShellCommandGetManFileNameDriver1, 0, L"Driver1", TRUE, gShellDriver1HiiHandle, STRING_TOKEN(STR_GET_HELP_DH) ); + ShellCommandRegisterCommandName(L"drivers", ShellCommandRunDrivers , ShellCommandGetManFileNameDriver1, 0, L"Driver1", TRUE, gShellDriver1HiiHandle, STRING_TOKEN(STR_GET_HELP_DRIVERS) ); + ShellCommandRegisterCommandName(L"devtree", ShellCommandRunDevTree , ShellCommandGetManFileNameDriver1, 0, L"Driver1", TRUE, gShellDriver1HiiHandle, STRING_TOKEN(STR_GET_HELP_DEVTREE) ); + ShellCommandRegisterCommandName(L"drvcfg", ShellCommandRunDrvCfg , ShellCommandGetManFileNameDriver1, 0, L"Driver1", TRUE, gShellDriver1HiiHandle, STRING_TOKEN(STR_GET_HELP_DRVCFG) ); + + return (EFI_SUCCESS); +} + +/** + Destructor for the library. free any resources. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. +**/ +EFI_STATUS +EFIAPI +UefiShellDriver1CommandsLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + if (gShellDriver1HiiHandle != NULL) { + HiiRemovePackages(gShellDriver1HiiHandle); + } + return (EFI_SUCCESS); +} + + + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.h new file mode 100644 index 00000000..21360b26 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.h @@ -0,0 +1,222 @@ +/** @file + Main file for NULL named library for Profile1 shell command functions. + + Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _UEFI_SHELL_DRIVER1_COMMANDS_LIB_H_ +#define _UEFI_SHELL_DRIVER1_COMMANDS_LIB_H_ + +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +extern EFI_HII_HANDLE gShellDriver1HiiHandle; +extern BOOLEAN gInReconnect; + +/** + Function for 'connect' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunConnect ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'devices' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunDevices ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'openinfo' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunOpenInfo ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'devtree' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunDevTree ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'dh' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunDh ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'disconnect' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunDisconnect ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'drivers' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunDrivers ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'drvcfg' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunDrvCfg ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'drvdiag' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunDrvDiag ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'reconnect' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunReconnect ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'unload' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunUnload ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Do a connect from an EFI variable via it's key name. + + @param[in] Key The name of the EFI Variable. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ShellConnectFromDevPaths ( + IN CONST CHAR16 *Key + ); + + + +#endif + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf new file mode 100644 index 00000000..75f46225 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf @@ -0,0 +1,68 @@ +## @file +# Provides shell driver1 profile functions +# +# Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiShellDriver1CommandsLib + FILE_GUID = 313D3674-3ED4-48fd-BF97-7DB35D4190D1 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = UefiShellDriver1CommandsLibConstructor + DESTRUCTOR = UefiShellDriver1CommandsLibDestructor + +[Sources] + Connect.c + Devices.c + OpenInfo.c + Disconnect.c + Reconnect.c + Unload.c + DrvDiag.c + Dh.c + Drivers.c + DevTree.c + DrvCfg.c + UefiShellDriver1CommandsLib.c + UefiShellDriver1CommandsLib.h + UefiShellDriver1CommandsLib.uni + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + ShellCommandLib + ShellLib + UefiLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + SortLib + PrintLib + PeCoffGetEntryPointLib + +[Pcd] + gEfiShellPkgTokenSpaceGuid.PcdShellProfileMask ## CONSUMES + +[Protocols] + gEfiDriverHealthProtocolGuid ## UNDEFINED + gEfiDriverFamilyOverrideProtocolGuid ## UNDEFINED + gEfiHiiConfigAccessProtocolGuid ## SOMETIMES_CONSUMES + gEfiHiiDatabaseProtocolGuid ## CONSUMES + +[Guids] + gEfiGlobalVariableGuid ## SOMETIMES_CONSUMES ## GUID + gEfiConsoleInDeviceGuid ## CONSUMES ## GUID + gEfiConsoleOutDeviceGuid ## CONSUMES ## GUID + gShellDriver1HiiGuid ## PRODUCES ## HII diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.uni b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.uni new file mode 100644 index 00000000..0e6799d0 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.uni @@ -0,0 +1,753 @@ +// /** +// +// (C) Copyright 2016-2017 Hewlett Packard Enterprise Development LP
+// (C) Copyright 2012-2015 Hewlett-Packard Development Company, L.P.
+// Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// Module Name: +// +// UefiShellDriver1CommandsLib.uni +// +// Abstract: +// +// String definitions for UEFI Shell 2.0 driver1 profile commands +// +// +// **/ + +/=# + +#langdef en-US "english" + +#string STR_GEN_PROBLEM #language en-US "%H%s%N: Unknown flag - '%H%s%N'\r\n" +#string STR_GEN_PROBLEM_VAL #language en-US "%H%s%N: Bad value - '%H%s%N' for flag - '%H%s%N'\r\n" +#string STR_GEN_PARAM_INV #language en-US "%H%s%N: Invalid argument - '%H%s%N'\r\n" +#string STR_GEN_TOO_FEW #language en-US "%H%s%N: Too few arguments\r\n" +#string STR_GEN_TOO_MANY #language en-US "%H%s%N: Too many arguments\r\n" +#string STR_GEN_INV_HANDLE #language en-US "%H%s%N: Handle - '%H%s%N' not found\r\n" +#string STR_GEN_PARAM_CONFLICT #language en-US "%H%s%N: Flags conflict with - '%H%s%N' and '%H%s%N'\r\n" +#string STR_GEN_NO_VALUE #language en-US "%H%s%N: Missing argument for flag - '%H%s%N'\r\n" +#string STR_GEN_HANDLE_NOT #language en-US "%H%s%N: Handle [%H%02x%N] is not a valid %s\r\n" +#string STR_GEN_HANDLE_REQ #language en-US "%H%s%N: Handle required with the specified options\r\n" +#string STR_GEN_PROTOCOL_NF #language en-US "%H%s%N: The protocol '%H%s%N' is required and not found (%g)\r\n" +#string STR_GEN_FIND_FAIL #language en-US "%H%s%N: File not found - '%H%s%N'\r\n" +#string STR_GEN_FILE_EXIST #language en-US "%H%s%N: File already exists - '%H%s%N'\r\n" +#string STR_GEN_FILE_OPEN_FAIL #language en-US "%H%s%N: Cannot open file - '%H%s%N'\r\n" +#string STR_FILE_WRITE_FAIL #language en-US "%H%s%N: Write file error - '%H%s%N'\r\n" +#string STR_FILE_READ_FAIL #language en-US "%H%s%N: Read file error - '%H%s%N'\r\n" +#string STR_GEN_OUT_MEM #language en-US "%H%s%N: Memory allocation was not successful\r\n" +#string STR_GEN_UEFI_FUNC_ERROR #language en-US "%H%s%N: UEFI function '%H%s%N' returned an incorrect value for: %s (%x)\r\n" +#string STR_GEN_UEFI_FUNC_WARN #language en-US "%H%s%N: UEFI function '%H%s%N' returned: %r\r\n" +#string STR_GEN_SFO_HEADER #language en-US "ShellCommand,"%s"\r\n" + +#string STR_DRVDIAG_HEADER #language en-US "%EAvailable Diagnostics%N.\r\n" +#string STR_DRVDIAG_DRIVER_HEADER #language en-US "Driver [%H%02x%N]: " +#string STR_DRVDIAG_DRIVER_NO_HANDLES #language en-US "No controller handles found.\r\n" + +#string STR_HANDLE_RESULT #language en-US "%H%s%N - Handle [%H%02x%N] Result %r.\r\n" +#string STR_3P_RESULT #language en-US "%H%s%N - (%H%02x%N,%H%02x%N,%H%02x%N) Result %r.\r\n" +#string STR_CONNECT_NONE #language en-US "%HConnect%N No drivers could be connected.\r\n" + +#string STR_DRVCFG_NONE_FOUND #language en-US "%HDrvCfg%N No configurable devices were found.\r\n" +#string STR_DRVCFG_COMP #language en-US "%HDrvCfg%N - operation complete.\r\n" +#string STR_DRVCFG_DONE_HII #language en-US "Handle[%H%02x%N] successfully updated from file.\r\n" +#string STR_DRVCFG_LINE_HII #language en-US "Handle[%H%02x%N] HII Config Access\r\n" +#string STR_DRVCFG_ALL_LANG #language en-US "Driver[%H%02x%N] Ctrl[--] Lang[%H%a%N] Driver Configuration" +#string STR_DRVCFG_CTRL_LANG #language en-US "Driver[%H%02x%N] Ctrl[%H%02x%N] Lang[%H%a%N] Driver Configuration" +#string STR_DRVCFG_CHILD_LANG #language en-US "Driver[%H%02x%N] Ctrl[%H%02x%N] Child[%H%02x%N] Lang[%H%a%N] Driver Configuration" +#string STR_DRVCFG_RESTART_S #language en-US "Restart %s\r\n" +#string STR_DRVCFG_STOP #language en-US "Stop Controller\n" +#string STR_DRVCFG_ENTER_S #language en-US "\nPress [ENTER] to %s" +#string STR_DRVCFG_NONE #language en-US "None\n" +#string STR_DRVCFG_CTLR_S #language en-US "Controller %s\n" +#string STR_DRVCFG_FORCE_D #language en-US "Force Default Configuration to DefaultType %08x\n" +#string STR_DRVCFG_VALIDATE #language en-US "Validate Configuration Options\n" +#string STR_DRVCFG_SET #language en-US "Set Configuration Options\n" +#string STR_DRVCFG_NOT_SUPPORT #language en-US "Handle [%H%02x%N] does not support configuration.\n" +#string STR_DRVCFG_OPTIONS_SET #language en-US " - Options set. Action Required is " +#string STR_DRVCFG_NOT_SET #language en-US " - Options not set. Status = %r\n" +#string STR_DRVCFG_DEF_FORCED #language en-US " - Defaults forced. Action Required is " +#string STR_DRVCFG_FORCE_FAILED #language en-US " - Force of defaults failed. Status = %r\n" +#string STR_DRVCFG_OPTIONS_VALID #language en-US " - Options valid\n" +#string STR_DRVCFG_OPTIONS_INV #language en-US " - Options not valid. Status = %r\n" +#string STR_DRVCFG_IN_FILE_NF #language en-US "DevicePath '%B%s%N' from file not found in HII DB. Skipped.\r\n" + + +#string STR_DEVICES_HEADER_LINES #language en-US "%N" +" T D\r\n" +" Y C I\r\n" +" P F A\r\n" +"CTRL E G G #P #D #C Device Name\r\n" +"==== = = = == == === =========================================================\r\n" +#string STR_DEVICES_ITEM_LINE #language en-US "%H%4x%N %1c %1c %1c %2d %2d %3d %s\r\n" +#string STR_DEVICES_ITEM_LINE_SFO #language en-US "DevicesInfo,"%x","%c","%c","%c","%d","%d","%d","%s"\r\n" + +#string STR_DRIVERS_HEADER_LINES #language en-US "%N" +"%H T D%N\r\n" +"%HD Y C I%N\r\n" +"%HR P F A%N\r\n" +"%HV VERSION E G G #D #C DRIVER NAME IMAGE NAME%N\r\n" +"== ======== = = = == == =================================== ==========\r\n" +#string STR_DRIVERS_ITEM_LINE #language en-US "%H%2x%N %08x %1c %1c %1c %2s %2s %-35s %s\r\n" +#string STR_DRIVERS_ITEM_LINE_SFO #language en-US "DriversInfo,"%x","%x","%c","%c","%c","%d","%d","%s","%s"\r\n" + +#string STR_DH_OUTPUT_DECODE #language en-US "%s: %g\r\n" +#string STR_DH_NO_NAME_FOUND #language en-US "Protocol Name '%s' could not be identified.\r\n" +#string STR_DH_NO_GUID_FOUND #language en-US "Protocol GUID '%g' could not be identified.\r\n" +#string STR_DH_SFO_OUTPUT #language en-US "%s, %s, %H%02x%N, %s, &s\r\n" +#string STR_DH_OUTPUT #language en-US "%H%02x%N: %s\r\n" +#string STR_DH_OUTPUT_ALL_HEADER #language en-US "Handle dump\r\n" +#string STR_DH_OUTPUT_GUID_HEADER #language en-US "Handle dump by protocol '%g'\r\n" +#string STR_DH_OUTPUT_NAME_HEADER #language en-US "Handle dump by protocol '%s'\r\n" +#string STR_DH_OUTPUT_SINGLE_D #language en-US "%H%02x%N: %s\r\n" +#string STR_DH_OUTPUT_SINGLE #language en-US "%H%02x%N: %x\r\n%s" +#string STR_DH_OUTPUT_SFO #language en-US "%s, %s, %s, %H%02x%N, %s, %s\r\n" +#string STR_DH_OUTPUT_DRIVER1 #language en-US " Controller Name : %H%s%N\r\n" +#string STR_DH_OUTPUT_DRIVER2 #language en-US " Device Path : %H%s%N\r\n" + " Controller Type : %H%s%N\r\n" + " Configuration : %H%s%N\r\n" + " Diagnostics : %H%s%N\r\n" +#string STR_DH_OUTPUT_DRIVER3 #language en-US " Managed by : %H%s%N\r\n" +#string STR_DH_OUTPUT_DRIVER4A #language en-US " Drv[%H%02x%N] : Image(%H%s%N)r\n" +#string STR_DH_OUTPUT_DRIVER4B #language en-US " Drv[%H%02x%N] : %H%s%N\r\n" +#string STR_DH_OUTPUT_DRIVER5 #language en-US " Parent Controllers : %H%s%N\r\n" +#string STR_DH_OUTPUT_DRIVER5B #language en-US " Parent[%H%02x%N] : %H%s%N\r\n" +#string STR_DH_OUTPUT_DRIVER6 #language en-US " Child Controllers : %H%s%N\r\n" +#string STR_DH_OUTPUT_DRIVER6B #language en-US " Child[%H%02x%N] : %H%s%N\r\n" +#string STR_DH_OUTPUT_DRIVER6C #language en-US " Child[%H%02x%N] : %H%s%N\r\n" +#string STR_DH_OUTPUT_DRIVER7 #language en-US " Driver Name [%H%02x%N] : %H%s%N\r\n" +#string STR_DH_OUTPUT_DRIVER7B #language en-US " Driver Image Name : %H%s%N\r\n" +#string STR_DH_OUTPUT_DRIVER8 #language en-US " Driver Version : %H%08x%N\r\n" + " Driver Type : %H%s%N\r\n" + " Configuration : %H%s%N\r\n" + " Diagnostics : %H%s%N\r\n" +#string STR_DH_OUTPUT_DRIVER9 #language en-US " Managing : %H%s%N\r\n" +#string STR_DH_OUTPUT_DRIVER9B #language en-US " Ctrl[%H%02x%N] : %H%s%N\r\n" + +#string STR_DEV_TREE_OUTPUT #language en-US "Ctrl[%H%02x%N] %s\r\n" + +#string STR_UNLOAD_CONF #language en-US "%HUnload%N - Handle [%H%02x%N]. [y/n]?\r\n" +#string STR_UNLOAD_VERBOSE #language en-US "" +"Handle [%H%02x%N] (%08x)\r\n" +" Image (%08x)\r\n" +" ParentHandle..: %08x\r\n" +" SystemTable...: %08x\r\n" +" DeviceHandle..: %08x\r\n" +" FilePath......: %s\r\n" +" PDBFileName...: %a\r\n" +" ImageBase.....: %08x\r\n" +" ImageSize.....: %Ld\r\n" +" CodeType......: %s\r\n" +" DataType......: %s\r\n" + +#string STR_OPENINFO_HEADER_LINE #language en-US "Handle %H%02x%N (%H%0p%N)\r\n" +#string STR_OPENINFO_LINE #language en-US " Drv[%H%02x%N] Ctrl[%H%02x%N] Cnt(%H%02x%N) %H%s Image%N(%s)\r\n" +#string STR_OPENINFO_MIN_LINE #language en-US " Drv[%H%02x%N] Ctrl[ ] Cnt(%H%02x%N) %H%s Image%N(%s)\r\n" + +#string STR_DRV_DIAG_ITEM_LINE #language en-US " Drv[%H%02x%N] Ctrl[%H%02x%N] Child[%H%02x%N]\r\n" + +#string STR_GET_HELP_DRVCFG #language en-US "" +".TH drvcfg 0 "configure a UEFI driver."\r\n" +".SH NAME\r\n" +"Invokes the driver configuration.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"DRVCFG [-l XXX] [-c] [-f |-v|-s] \r\n" +" [DriverHandle [DeviceHandle [ChildHandle]]] [-i filename] [-o filename]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -c - Configures all child devices.\r\n" +" -l - Configures using the ISO 3066 language specified by XXX.\r\n" +" -f - Forces defaults.\r\n" +" -v - Validates options.\r\n" +" -s - Sets options.\r\n" +" -i - Receives configuration updates from an input file.\r\n" +" -o - Exports the settings of the specified driver instance to a\r\n" +" file.\r\n" +" Type - Specifies the type of default configuration options to force on the\r\n" +" controller.\r\n" +" 0 - Standard Defaults.\r\n" +" 1 - Manufacturing Defaults.\r\n" +" 2 - Safe Defaults.\r\n" +" 4000-FFFF - Custom Defaults.\r\n" +" DriverHandle - Specifies the the handle of the driver to configure.\r\n" +" DeviceHandle - Specifies the handle of a device that the DriverHandle is managing.\r\n" +" ChildHandle - Specifies the handle of a device that is a child of the DeviceHandle. \r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. Default Type:\r\n" +" 0 - Safe Defaults. Places a controller in a safe configuration with\r\n" +" the greatest probability of functioning correctly in a platform.\r\n" +" 1 - Manufacturing Defaults. Optional type that places the controller in\r\n" +" a configuration suitable for a manufacturing and test environment.\r\n" +" 2 - Custom Defaults. Optional type that places the controller in a\r\n" +" custom configuration.\r\n" +" 3 - Performance Defaults. Optional type that places the controller in a\r\n" +" configuration that maximizes the controller's performance in a \r\n" +" platform. \r\n" +" Other Value - Depends on the driver's implementation.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display the list of devices that are available for configuration:\r\n" +" Shell> drvcfg\r\n" +" \r\n" +" * To display the list of devices and child devices that are available for\r\n" +" configuration:\r\n" +" Shell> drvcfg -c\r\n" +" \r\n" +" * To force defaults on all devices:\r\n" +" Shell> drvcfg -f 0\r\n" +" \r\n" +" * To force defaults on all devices that are managed by driver 0x17:\r\n" +" Shell> drvcfg -f 0 17\r\n" +" \r\n" +" * To force defaults on device 0x28 that is managed by driver 0x17:\r\n" +" Shell> drvcfg -f 0 17 28\r\n" +" \r\n" +" * To force defaults on all child devices of device 0x28 that is managed by\r\n" +" driver 0x17:\r\n" +" Shell> drvcfg -f 0 17 28 -c\r\n" +" \r\n" +" * To force defaults on child device 0x30 of device 0x28 that is managed by\r\n" +" driver 0x17:\r\n" +" Shell> drvcfg -f 0 17 28 30\r\n" +" \r\n" +" * To validate options on all devices:\r\n" +" Shell> drvcfg -v\r\n" +" \r\n" +" * To validate options on all devices that are managed by driver 0x17:\r\n" +" Shell> drvcfg -v 17\r\n" +" \r\n" +" * To validate options on device 0x28 that is managed by driver 0x17:\r\n" +" Shell> drvcfg -v 17 28\r\n" +" \r\n" +" * To validate options on all child devices of device 0x28 that is managed by\r\n" +" driver 0x17:\r\n" +" Shell> drvcfg -v 17 28 -c\r\n" +" \r\n" +" * To validate options on child device 0x30 of device 0x28 that is managed by\r\n" +" driver 0x17:\r\n" +" Shell> drvcfg -v 17 28 30\r\n" +" \r\n" +" * To set options on device 0x28 that is managed by driver 0x17: \r\n" +" Shell> drvcfg -s 17 28\r\n" +" \r\n" +" * To set options on child device 0x30 of device 0x28 that is managed by\r\n" +" driver 0x17:\r\n" +" Shell> drvcfg -s 17 28 30\r\n" +" \r\n" +" * To set options on device 0x28 that is managed by driver 0x17 in English:\r\n" +" Shell> drvcfg -s 17 28 -l eng\r\n" +" \r\n" +" * To set options on device 0x28 that is managed by driver 0x17 in Spanish:\r\n" +" Shell> drvcfg -s 17 28 -l spa\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_UNSUPPORTED The action as requested was unsupported.\r\n" +" SHELL_INVALID_PARAMETER One of the passed in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" + +#string STR_GET_HELP_DRIVERS #language en-US "" +".TH drivers 0 "display a list of drivers"\r\n" +".SH NAME\r\n" +"Displays the UEFI driver list.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"DRIVERS [-l XXX] [-sfo] \r\n" +".SH OPTIONS\r\n" +" \r\n" +" -l - Displays drivers using the specified language (e.g. ISO 639-2) \r\n" +" -sfo - Displays information as described in Standard-Format Output.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command displays a list of information for drivers that follow the\r\n" +" UEFI Driver Model in the UEFI environment. The list includes:\r\n" +" DRV - The handle number of the UEFI driver.\r\n" +" VERSION - The version number of the UEFI driver.\r\n" +" TYPE - The driver type:\r\n" +" [B] - Bus Driver\r\n" +" [D] - Device Driver\r\n" +" CFG - Driver supports the Driver Configuration Protocol.\r\n" +" DIAG - Driver supports the Driver Diagnostics Protocol.\r\n" +" #D - The number of devices that this driver is managing.\r\n" +" #C - The number of child devices that this driver has produced.\r\n" +" DRIVER NAME - The name of the driver from the Component Name Protocol.\r\n" +" IMAGE PATH - The file path from which the driver was loaded.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display the list:\r\n" +" Shell> drivers\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_INVALID_PARAMETER One of the passed in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" + +#string STR_GET_HELP_DISCONNECT #language en-US "" +".TH disconnect 0 "disconnect a driver"\r\n" +".SH NAME\r\n" +"Disconnects one or more drivers from the specified devices. \r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"DISCONNECT DeviceHandle [DriverHandle [ChildHandle]] \r\n" +"DISCONNECT -r [-nc] \r\n" +".SH OPTIONS\r\n" +" \r\n" +"NOTES:\r\n" +" -r - Disconnects all drivers from all devices, then reconnect\r\n" +" consoles.\r\n" +" -nc - Do not reconnect the console devices.\r\n" +" DeviceHandle - Specifies a device handle (a hexadecimal number). If not\r\n" +" specified, then disconnect DriverHandle.\r\n" +" DriverHandle - Specifies a driver handle (a hexadecimal number).\r\n" +" ChildHandle - Specifies a child handle of a device (a hexadecimal number).\r\n" +" If not specified, then all child handles of DeviceHandle are\r\n" +" disconnected.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. If the 'DriverHandle' parameter is not specified, the default is to\r\n" +" disconnect 'DeviceHandle'.\r\n" +" 2. If the 'ChildHandle' parameter is not specified, the default is to\r\n" +" disconnect all child handles of the 'DeviceHandle'.\r\n" +" 3. If the '-r' option is specified, all consoles and drivers will be\r\n" +" disconnected from all devices in the system, then consoles are\r\n" +" reconnected. If the '-nc' option is also spcified, then console devices\r\n" +" are not reconnected.\r\n" +" 4. This command does not support output redirection.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To disconnect all drivers from all devices, then reconnect console\r\n" +" devices:\r\n" +" Shell> disconnect -r\r\n" +" \r\n" +" * To disconnect all drivers from all devices, including console devices:\r\n" +" Shell> disconnect -r -nc\r\n" +" \r\n" +" * To disconnect all drivers from device 0x28:\r\n" +" fs0:\> disconnect 28\r\n" +" \r\n" +" * To disconnect driver 0x17 from device 0x28:\r\n" +" fs0:\> disconnect 28 17\r\n" +" \r\n" +" * To disconnect driver 0x17 from controlling the child 0x32 of device 0x28:\r\n" +" fs0:\> disconnect 28 17 32\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_INVALID_PARAMETER One of the passed in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" + +#string STR_GET_HELP_DH #language en-US "" +".TH dh 0 "displays list of handles"\r\n" +".SH NAME\r\n" +"Displays the device handles in the UEFI environment. \r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"DH [-l ] [handle | -p ] [-d] [-v] \r\n" +".SH OPTIONS\r\n" +" \r\n" +" -p - Dumps all handles of a protocol specified by the GUID.\r\n" +" -d - Dumps UEFI Driver Model-related information.\r\n" +" -l - Dumps information using the language codes (e.g. ISO 639-2).\r\n" +" -sfo - Displays information as described in Standard-Format Output.\r\n" +" -v - Dumps verbose information about a specific handle.\r\n" +" handle - Specifies a handle to dump information about (a hexadecimal number).\r\n" +" If not present, then all information will be dumped.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. When neither 'handle' nor 'prot_id' is specified, a list of all the\r\n" +" device handles in the UEFI environment is displayed. \r\n" +" 2. The '-d' option displays UEFI Driver Model related information including\r\n" +" parent handles, child handles, all drivers installed on the handle, etc.\r\n" +" 3. The '-v' option displays verbose information for the specified handle\r\n" +" including all the protocols on the handle and their details.\r\n" +" 4. If the '-p' option is specified, all handles containing the specified\r\n" +" protocol will be displayed. Otherwise, the 'handle' parameter has to be\r\n" +" specified for display. In this case, the '-d' option will be enabled\r\n" +" automatically if the '-v' option is not specified.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display all handles and display one screen at a time:\r\n" +" Shell> dh -b\r\n" +" \r\n" +" * To display the detailed information on handle 0x30:\r\n" +" Shell> dh 30\r\n" +" \r\n" +" * To display all handles with 'diskio' protocol:\r\n" +" Shell> dh -p diskio\r\n" +" \r\n" +" * To display all handles with 'LoadedImage' protocol and break when the screen is\r\n" +" full:\r\n" +" Shell> dh -p LoadedImage -b\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_INVALID_PARAMETER One of the passed in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" + +#string STR_GET_HELP_DEVTREE #language en-US "" +".TH devtree 0 "display device tree"\r\n" +".SH NAME\r\n" +"Displays the UEFI Driver Model compliant device tree.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"DEVTREE [-b] [-d] [-l XXX] [DeviceHandle] \r\n" +".SH OPTIONS\r\n" +" \r\n" +" -b - Displays one screen at a time.\r\n" +" -d - Displays the device tree using device paths.\r\n" +" -l - Displays the device tree using the specified language.\r\n" +" DeviceHandle - Displays the device tree below a certain handle.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command prints a tree of devices that are being managed by drivers\r\n" +" that follow the UEFI Driver Model. By default, the devices are printed in\r\n" +" device names that are retrieved from the Component Name Protocol.\r\n" +" 2. If the option -d is specified, the device paths will be printed instead.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display the tree of all devices compliant with the UEFI Driver Model:\r\n" +" Shell> devtree\r\n" +" \r\n" +" * To display the tree of all devices below device 28 compliant with the UEFI\r\n" +" Driver Model:\r\n" +" Shell> devtree 28\r\n" +" \r\n" +" * To display the tree of all devices compliant with the UEFI Driver Model\r\n" +" one screen at a time:\r\n" +" Shell> devtree -b\r\n" +" \r\n" + +#string STR_GET_HELP_DEVICES #language en-US "" +".TH devices 0 "display a list of devices"\r\n" +".SH NAME\r\n" +"Displays the list of devices managed by UEFI drivers. \r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"DEVICES [-b] [-l XXX] [-sfo] \r\n" +".SH OPTIONS\r\n" +" \r\n" +" -b - Display one screen at a time\r\n" +" -l XXX - Display devices using the specified ISO 639-2 language\r\n" +" -sfo - Displays information as described in Standard-Format Output.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. The command prints a list of devices that are being managed by drivers\r\n" +" that follow the UEFI Driver Model.\r\n" +" 2. Display Format:\r\n" +" CTRL - The handle number of the UEFI device\r\n" +" TYPE - The device type:\r\n" +" [R] - Root Controller\r\n" +" [B] - Bus Controller\r\n" +" [D] - Device Controller\r\n" +" CFG - A managing driver supports the Driver Configuration\r\n" +" Protocol. Yes if 'Y' or 'X'; No if 'N' or '-'.\r\n" +" DIAG - A managing driver supports the Driver Diagnostics\r\n" +" Protocol. Yes if 'Y' or 'X'; No if 'N' or '-'.\r\n" +" #P - The number of parent controllers for this device\r\n" +" #D - The number of drivers managing the device\r\n" +" #C - The number of child controllers produced by this device\r\n" +" DEVICE NAME - The name of the device from the Component Name Protocol\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display all devices compliant with the UEFI Driver Model:\r\n" +" Shell> devices\r\n" +" \r\n" + +#string STR_GET_HELP_CONNECT #language en-US "" +".TH connect 0 "connect a driver"\r\n" +".SH NAME\r\n" +"Binds a driver to a specific device and starts the driver. \r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"CONNECT [[DeviceHandle] [DriverHandle] | [-c] | [-r]] \r\n" +".SH OPTIONS\r\n" +" \r\n" +" -c - Connects console devices\r\n" +" -r - Connects recursively\r\n" +" DeviceHandle - Specifies a device handle in hexadecimal format.\r\n" +" DriverHandle - Specifies a driver handle in hexadecimal format.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. If no 'DeviceHandle' parameter is specified, all device handles in the\r\n" +" current system will be the default.\r\n" +" 2. If no 'DriverHandle' parameter is specified, all matched drivers will be\r\n" +" bound to the specified device.\r\n" +" 3. If 'DriverHandle' parameter is provided, the specified driver will have\r\n" +" highest priority on connecting the device(s).\r\n" +" 4. If the '-c' option is specified, only console devices described in the\r\n" +" UEFI Shell environment variables and related devices will be connected.\r\n" +" 5. If the '-r' option is specified, the command will recursively scan all\r\n" +" handles and check to see if any loaded or embedded driver can match the\r\n" +" specified device. If so, the driver will be bound to the device.\r\n" +" Additionally, if more device handles are created during the binding, \r\n" +" these handles will also be checked to see if a matching driver can bind\r\n" +" to these devices as well. The process is repeated until no more drivers\r\n" +" are able to connect to any devices. However, without the option, the\r\n" +" newly created device handles will not be further bound to any\r\n" +" drivers.\r\n" +" 6. If only a single handle is specified and the handle has an\r\n" +" EFI_DRIVER_BINDING_PROTOCOL on it, then the handle is assumed to be a\r\n" +" driver handle. Otherwise, it is assumed to be a device handle.\r\n" +" 7. If no parameters are specified, then the command will attempt to bind\r\n" +" all proper drivers to all devices without recursion. Each connection\r\n" +" status will be displayed.\r\n" +" 8. Output redirection is not supported for 'connect -r' usage.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To connect all drivers to all devices recursively:\r\n" +" Shell> connect -r\r\n" +" \r\n" +" * To display all connections:\r\n" +" Shell> connect\r\n" +" \r\n" +" * To connect drivers with 0x17 as highest priority to all the devices they\r\n" +" can manage:\r\n" +" Shell> connect 17\r\n" +" \r\n" +" * To connect all possible drivers to device 0x19:\r\n" +" Shell> connect 19\r\n" +" \r\n" +" * To connect drivers with 0x17 as highest priority to device 0x19 they can\r\n" +" manage:\r\n" +" Shell> connect 19 17\r\n" +" \r\n" +" * To connect console devices described in the UEFI Shell environment\r\n" +" variables:\r\n" +" Shell> connect -c\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_INVALID_PARAMETER One of the passed in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" + +#string STR_GET_HELP_OPENINFO #language en-US "" +".TH openinfo 0 "display info about a handle."\r\n" +".SH NAME\r\n" +"Displays the protocols and agents associated with a handle. \r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"OPENINFO Handle [-b] \r\n" +".SH OPTIONS\r\n" +" \r\n" +" -b - Displays one screen at a time.\r\n" +" Handle - Displays open protocol information for the specified handle.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command is used to display the open protocols on a given handle.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To show open protocols on handle 0x23:\r\n" +" Shell> openinfo 23\r\n" +" \r\n" + +#string STR_GET_HELP_DRVDIAG #language en-US "" +".TH drvdiag 0 "diagnose a driver"\r\n" +".SH NAME\r\n" +"Invokes the Driver Diagnostics Protocol. \r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"DRVDIAG [-c] [-l XXX] [-s|-e|-m] [DriverHandle [DeviceHandle [ChildHandle]]] \r\n" +".SH OPTIONS\r\n" +" \r\n" +" -c - Diagnoses all child devices.\r\n" +" -l - Diagnoses using the ISO 639-2 language specified by XXX.\r\n" +" -s - Runs diagnostics in standard mode.\r\n" +" -e - Runs diagnostics in extended mode.\r\n" +" -m - Runs diagnostics in manufacturing mode.\r\n" +" DriverHandle - Specifies the handle of the driver to diagnose.\r\n" +" DeviceHandle - Specifies the handle of a device that DriverHandle is managing.\r\n" +" ChildHandle - Specifies the handle of a device that is a child of DeviceHandle.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command invokes the Driver Diagnostics Protocol.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display the list of devices that are available for diagnostics:\r\n" +" Shell> drvdiag\r\n" +" \r\n" +" * To display the list of devices and child devices that are available for\r\n" +" diagnostics:\r\n" +" Shell> drvdiag -c\r\n" +" \r\n" +" * To run diagnostics in standard mode on all devices:\r\n" +" Shell> drvdiag -s\r\n" +" \r\n" +" * To run diagnostics in standard mode on all devices in English:\r\n" +" Shell> drvdiag -s -l eng\r\n" +" \r\n" +" * To run diagnostics in standard mode on all devices in Spanish:\r\n" +" Shell> drvdiag -s -l spa\r\n" +" \r\n" +" * To run diagnostics in standard mode on all devices and child devices:\r\n" +" Shell> drvdiag -s -c\r\n" +" \r\n" +" * To run diagnostics in extended mode on all devices:\r\n" +" Shell> drvdiag -e\r\n" +" \r\n" +" * To run diagnostics in manufacturing mode on all devices:\r\n" +" Shell> drvdiag -m\r\n" +" \r\n" +" * To run diagnostics in standard mode on all devices managed by driver 0x17:\r\n" +" Shell> drvdiag -s 17\r\n" +" \r\n" +" * To run diagnostics in standard mode on device 0x28 managed by driver 0x17:\r\n" +" Shell> drvdiag -s 17 28\r\n" +" \r\n" +" * To run diagnostics in standard mode on all child devices of device 0x28\r\n" +" managed by driver 0x17:\r\n" +" Shell> drvdiag -s 17 28 -c\r\n" +" \r\n" +" * To run diagnostics in standard mode on child device 0x30 of device 0x28\r\n" +" managed by driver 0x17:\r\n" +" Shell> drvdiag -s 17 28 30\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_INVALID_PARAMETER One of the passed in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" + +#string STR_GET_HELP_RECONNECT #language en-US "" +".TH reconnect 0 "reconnect drivers"\r\n" +".SH NAME\r\n" +"Reconnects drivers to the specific device. \r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"RECONNECT DeviceHandle [DriverHandle [ChildHandle]]\r\n" +"RECONNECT -r \r\n" +".SH OPTIONS\r\n" +" \r\n" +" -r - Reconnects drivers to all devices.\r\n" +" DeviceHandle - Specifies a device handle (a hexadecimal number).\r\n" +" DriverHandle - Specifies a driver handle (a hexadecimal number). If not specified, all\r\n" +" drivers on the specified device will be reconnected. \r\n" +" ChildHandle - Specifies the child handle of device (a hexadecimal number). If not\r\n" +" specified, then all child handles of the specified device are\r\n" +" reconnected.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command reconnects drivers to the specific device. It will first\r\n" +" disconnect the specified driver from the specified device and then connect\r\n" +" the driver to the device recursively.\r\n" +" 2. If the -r option is used, then all drivers will be reconnected to all\r\n" +" devices. Any drivers that are bound to any devices will be disconnected\r\n" +" first and then connected recursively.\r\n" +" 3. See the connect and disconnect commands for more details. \r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To reconnect all drivers to all devices:\r\n" +" Shell> reconnect -r\r\n" +" \r\n" +" * To reconnect all drivers to device 0x28:\r\n" +" fs0:\> reconnect 28\r\n" +" \r\n" +" * To disconnect 0x17 from 0x28 then reconnect drivers with 0x17 as highest\r\n" +" priority to device 0x28:\r\n" +" fs0:\> reconnect 28 17\r\n" +" \r\n" +" * To disconnect 0x17 from 0x28 destroying child 0x32 then reconnect drivers\r\n" +" with 0x17 as highest priority to device 0x28\r\n" +" fs0:\> reconnect 28 17 32\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_INVALID_PARAMETER One of the passed in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" + +#string STR_GET_HELP_UNLOAD #language en-US "" +".TH unload 0 "unload a driver"\r\n" +".SH NAME\r\n" +"Unloads a driver image that was already loaded. \r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"UNLOAD [-n] [-v|-verbose] Handle \r\n" +".SH OPTIONS\r\n" +" \r\n" +" -n - Skips all prompts during unloading, so that it can be used\r\n" +" in a script file.\r\n" +" -v, -verbose - Dumps verbose status information before the image is unloaded.\r\n" +" Handle - Specifies the handle of driver to unload, always taken as hexadecimal number.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. The '-n' option can be used to skip all prompts during unloading.\r\n" +" 2. If the '-v' option is specified, verbose image information will be\r\n" +" displayed before the image is unloaded.\r\n" +" 3. Only drivers that support unloading can be successfully unloaded.\r\n" +" 4. Use the 'LOAD' command to load a driver.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To find the handle for the UEFI driver image to unload:\r\n" +" Shell> dh -b\r\n" +" \r\n" +" * To unload the UEFI driver image with handle 27:\r\n" +" Shell> unload 27\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_INVALID_PARAMETER One of the passed in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" + + + + + + + + + + + + + + + + + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Unload.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Unload.c new file mode 100644 index 00000000..2e2220fb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDriver1CommandsLib/Unload.c @@ -0,0 +1,142 @@ +/** @file + Main file for Unload shell Driver1 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellDriver1CommandsLib.h" + +/** + Function to dump LoadedImage info from TheHandle. + + @param[in] TheHandle The handle to dump info from. + + @retval EFI_SUCCESS The info was dumped. + @retval EFI_INVALID_PARAMETER The handle did not have LoadedImage +**/ +EFI_STATUS +DumpLoadedImageProtocolInfo ( + IN EFI_HANDLE TheHandle + ) +{ + CHAR16 *TheString; + + TheString = GetProtocolInformationDump(TheHandle, &gEfiLoadedImageProtocolGuid, TRUE); + + ShellPrintEx(-1, -1, L"%s", TheString); + + SHELL_FREE_NON_NULL(TheString); + + return (EFI_SUCCESS); +} + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-n", TypeFlag}, + {L"-v", TypeFlag}, + {L"-verbose", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'unload' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunUnload ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + EFI_HANDLE TheHandle; + CONST CHAR16 *Param1; + SHELL_PROMPT_RESPONSE *Resp; + UINT64 Value; + + ShellStatus = SHELL_SUCCESS; + Package = NULL; + Resp = NULL; + Value = 0; + TheHandle = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDriver1HiiHandle,L"unload", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetCount(Package) > 2){ + // + // error for too many parameters + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDriver1HiiHandle, L"unload"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetCount(Package) < 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDriver1HiiHandle, L"unload"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Param1 = ShellCommandLineGetRawValue(Package, 1); + if (Param1 != NULL) { + Status = ShellConvertStringToUint64(Param1, &Value, TRUE, FALSE); + TheHandle = ConvertHandleIndexToHandle((UINTN)Value); + } + + if (EFI_ERROR(Status) || Param1 == NULL || TheHandle == NULL){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"unload", Param1); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(TheHandle != NULL); + if (ShellCommandLineGetFlag(Package, L"-v") || ShellCommandLineGetFlag(Package, L"-verbose")) { + DumpLoadedImageProtocolInfo(TheHandle); + } + + if (!ShellCommandLineGetFlag(Package, L"-n")) { + Status = ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_UNLOAD_CONF), gShellDriver1HiiHandle, (UINTN)TheHandle); + Status = ShellPromptForResponse(ShellPromptResponseTypeYesNo, NULL, (VOID**)&Resp); + } + if (ShellCommandLineGetFlag(Package, L"-n") || (Resp != NULL && *Resp == ShellPromptResponseYes)) { + Status = gBS->UnloadImage(TheHandle); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HANDLE_RESULT), gShellDriver1HiiHandle, L"Unload", (UINTN)TheHandle, Status); + } + SHELL_FREE_NON_NULL(Resp); + } + } + } + if (ShellStatus == SHELL_SUCCESS) { + if (Status == EFI_SECURITY_VIOLATION) { + ShellStatus = SHELL_SECURITY_VIOLATION; + } else if (Status == EFI_INVALID_PARAMETER) { + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (EFI_ERROR(Status)) { + ShellStatus = SHELL_NOT_FOUND; + } + } + + if (Package != NULL) { + ShellCommandLineFreeVarList(Package); + } + + return (ShellStatus); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.c new file mode 100644 index 00000000..258ba6ef --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.c @@ -0,0 +1,53 @@ +/** @file + Main file for NULL named library for install1 shell command functions. + + Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +/** + Constructor for the Shell Level 1 Commands library. + + Install the handlers for level 1 UEFI Shell 2.0 commands. + + @param ImageHandle the image handle of the process + @param SystemTable the EFI System Table pointer + + @retval EFI_SUCCESS the shell command handlers were installed sucessfully + @retval EFI_UNSUPPORTED the shell level required was not found. +**/ +EFI_STATUS +EFIAPI +ShellInstall1CommandsLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + // + // check our bit of the profiles mask + // + if ((PcdGet8(PcdShellProfileMask) & BIT2) == 0) { + return (EFI_SUCCESS); + } + + return (BcfgLibraryRegisterBcfgCommand(ImageHandle, SystemTable, L"Install1")); +} + +/** + Destructor for the library. free any resources. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. +**/ +EFI_STATUS +EFIAPI +ShellInstall1CommandsLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return (BcfgLibraryUnregisterBcfgCommand(ImageHandle, SystemTable)); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.inf new file mode 100644 index 00000000..e6b5cc59 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.inf @@ -0,0 +1,46 @@ +## @file +# Provides shell install1 functions +# +# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiShellInstall1CommandsLib + FILE_GUID = D250E364-51C6-49ed-AEBF-6D83F5130F74 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = ShellInstall1CommandsLibConstructor + DESTRUCTOR = ShellInstall1CommandsLibDestructor + +[Sources.common] + UefiShellInstall1CommandsLib.c + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + ShellCommandLib + ShellLib + UefiLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + SortLib + PrintLib + BcfgCommandLib + +[Pcd] + gEfiShellPkgTokenSpaceGuid.PcdShellProfileMask ## CONSUMES + +[Guids] + gShellInstall1HiiGuid ## UNDEFINED diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/Exit.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/Exit.c new file mode 100644 index 00000000..5d175e51 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/Exit.c @@ -0,0 +1,91 @@ +/** @file + Main file for exit shell level 1 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel1CommandsLib.h" + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"/b", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'exit' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunExit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + UINT64 RetVal; + CONST CHAR16 *Return; + + ShellStatus = SHELL_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel1HiiHandle, L"exit", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + + // + // return the specified error code + // + Return = ShellCommandLineGetRawValue(Package, 1); + if (Return != NULL) { + Status = ShellConvertStringToUint64(Return, &RetVal, FALSE, FALSE); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel1HiiHandle, L"exit", Return); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // If we are in a batch file and /b then pass TRUE otherwise false... + // + ShellCommandRegisterExit((BOOLEAN)(gEfiShellProtocol->BatchIsActive() && ShellCommandLineGetFlag(Package, L"/b")), RetVal); + + ShellStatus = SHELL_SUCCESS; + } + } else { + // If we are in a batch file and /b then pass TRUE otherwise false... + // + ShellCommandRegisterExit((BOOLEAN)(gEfiShellProtocol->BatchIsActive() && ShellCommandLineGetFlag(Package, L"/b")), 0); + + ShellStatus = SHELL_SUCCESS; + } + + ShellCommandLineFreeVarList (Package); + } + return (ShellStatus); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/For.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/For.c new file mode 100644 index 00000000..2181c0d3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/For.c @@ -0,0 +1,745 @@ +/** @file + Main file for endfor and for shell level 1 functions. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel1CommandsLib.h" +#include + +/** + Determine if a valid string is a valid number for the 'for' command. + + @param[in] Number The pointer to the string representation of the number to test. + + @retval TRUE The number is valid. + @retval FALSE The number is not valid. +**/ +BOOLEAN +ShellIsValidForNumber ( + IN CONST CHAR16 *Number + ) +{ + if (Number == NULL || *Number == CHAR_NULL) { + return (FALSE); + } + + if (*Number == L'-') { + Number++; + } + + if (StrLen(Number) == 0) { + return (FALSE); + } + + if (StrLen(Number) >= 7) { + if ((StrStr(Number, L" ") == NULL) || (((StrStr(Number, L" ") != NULL) && (StrStr(Number, L" ") - Number) >= 7))) { + return (FALSE); + } + } + + if (!ShellIsDecimalDigitCharacter(*Number)) { + return (FALSE); + } + + return (TRUE); +} + +/** + Function for 'endfor' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunEndFor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + BOOLEAN Found; + SCRIPT_FILE *CurrentScriptFile; + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + if (!gEfiShellProtocol->BatchIsActive()) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"endfor"); + return (SHELL_UNSUPPORTED); + } + + if (gEfiShellParametersProtocol->Argc > 1) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel1HiiHandle, L"endfor"); + return (SHELL_INVALID_PARAMETER); + } + + Found = MoveToTag(GetPreviousNode, L"for", L"endfor", NULL, ShellCommandGetCurrentScriptFile(), FALSE, FALSE, FALSE); + + if (!Found) { + CurrentScriptFile = ShellCommandGetCurrentScriptFile(); + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_SYNTAX_NO_MATCHING), + gShellLevel1HiiHandle, + L"For", + L"EndFor", + CurrentScriptFile!=NULL + && CurrentScriptFile->CurrentCommand!=NULL + ? CurrentScriptFile->CurrentCommand->Line:0); + return (SHELL_NOT_FOUND); + } + return (SHELL_SUCCESS); +} + +typedef struct { + UINT32 Signature; + INTN Current; + INTN End; + INTN Step; + CHAR16 *ReplacementName; + CHAR16 *CurrentValue; + BOOLEAN RemoveSubstAlias; + CHAR16 Set[1]; + } SHELL_FOR_INFO; +#define SIZE_OF_SHELL_FOR_INFO OFFSET_OF (SHELL_FOR_INFO, Set) +#define SHELL_FOR_INFO_SIGNATURE SIGNATURE_32 ('S', 'F', 'I', 's') + +/** + Update the value of a given alias on the list. If the alias is not there then add it. + + @param[in] Alias The alias to test for. + @param[in] CommandString The updated command string. + @param[in, out] List The list to search. + + @retval EFI_SUCCESS The operation was completed successfully. + @retval EFI_OUT_OF_RESOURCES There was not enough free memory. +**/ +EFI_STATUS +InternalUpdateAliasOnList( + IN CONST CHAR16 *Alias, + IN CONST CHAR16 *CommandString, + IN OUT LIST_ENTRY *List + ) +{ + ALIAS_LIST *Node; + BOOLEAN Found; + + // + // assert for NULL parameter + // + ASSERT(Alias != NULL); + + // + // check for the Alias + // + for ( Node = (ALIAS_LIST *)GetFirstNode(List), Found = FALSE + ; !IsNull(List, &Node->Link) + ; Node = (ALIAS_LIST *)GetNextNode(List, &Node->Link) + ){ + ASSERT(Node->CommandString != NULL); + ASSERT(Node->Alias != NULL); + if (StrCmp(Node->Alias, Alias)==0) { + FreePool(Node->CommandString); + Node->CommandString = NULL; + Node->CommandString = StrnCatGrow(&Node->CommandString, NULL, CommandString, 0); + Found = TRUE; + break; + } + } + if (!Found) { + Node = AllocateZeroPool(sizeof(ALIAS_LIST)); + if (Node == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + ASSERT(Node->Alias == NULL); + Node->Alias = StrnCatGrow(&Node->Alias, NULL, Alias, 0); + ASSERT(Node->CommandString == NULL); + Node->CommandString = StrnCatGrow(&Node->CommandString, NULL, CommandString, 0); + InsertTailList(List, &Node->Link); + } + return (EFI_SUCCESS); +} + +/** + Find out if an alias is on the given list. + + @param[in] Alias The alias to test for. + @param[in] List The list to search. + + @retval TRUE The alias is on the list. + @retval FALSE The alias is not on the list. +**/ +BOOLEAN +InternalIsAliasOnList( + IN CONST CHAR16 *Alias, + IN CONST LIST_ENTRY *List + ) +{ + ALIAS_LIST *Node; + + // + // assert for NULL parameter + // + ASSERT(Alias != NULL); + + // + // check for the Alias + // + for ( Node = (ALIAS_LIST *)GetFirstNode(List) + ; !IsNull(List, &Node->Link) + ; Node = (ALIAS_LIST *)GetNextNode(List, &Node->Link) + ){ + ASSERT(Node->CommandString != NULL); + ASSERT(Node->Alias != NULL); + if (StrCmp(Node->Alias, Alias)==0) { + return (TRUE); + } + } + return (FALSE); +} + +/** + Remove an alias from the given list. + + @param[in] Alias The alias to remove. + @param[in, out] List The list to search. +**/ +BOOLEAN +InternalRemoveAliasFromList( + IN CONST CHAR16 *Alias, + IN OUT LIST_ENTRY *List + ) +{ + ALIAS_LIST *Node; + + // + // assert for NULL parameter + // + ASSERT(Alias != NULL); + + // + // check for the Alias + // + for ( Node = (ALIAS_LIST *)GetFirstNode(List) + ; !IsNull(List, &Node->Link) + ; Node = (ALIAS_LIST *)GetNextNode(List, &Node->Link) + ){ + ASSERT(Node->CommandString != NULL); + ASSERT(Node->Alias != NULL); + if (StrCmp(Node->Alias, Alias)==0) { + RemoveEntryList(&Node->Link); + FreePool(Node->Alias); + FreePool(Node->CommandString); + FreePool(Node); + return (TRUE); + } + } + return (FALSE); +} + +/** + Function to determine whether a string is decimal or hex representation of a number + and return the number converted from the string. + + @param[in] String String representation of a number + + @return the number + @retval (UINTN)(-1) An error ocurred. +**/ +UINTN +ReturnUintn( + IN CONST CHAR16 *String + ) +{ + UINT64 RetVal; + + if (!EFI_ERROR(ShellConvertStringToUint64(String, &RetVal, FALSE, TRUE))) { + return ((UINTN)RetVal); + } + return ((UINTN)(-1)); +} + +/** + Function for 'for' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunFor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + SCRIPT_FILE *CurrentScriptFile; + CHAR16 *ArgSet; + CHAR16 *ArgSetWalker; + CHAR16 *Parameter; + UINTN ArgSize; + UINTN LoopVar; + SHELL_FOR_INFO *Info; + CHAR16 *TempString; + CHAR16 *TempSpot; + BOOLEAN FirstPass; + EFI_SHELL_FILE_INFO *Node; + EFI_SHELL_FILE_INFO *FileList; + UINTN NewSize; + + ArgSet = NULL; + ArgSize = 0; + ShellStatus = SHELL_SUCCESS; + ArgSetWalker = NULL; + TempString = NULL; + Parameter = NULL; + FirstPass = FALSE; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + if (!gEfiShellProtocol->BatchIsActive()) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"for"); + return (SHELL_UNSUPPORTED); + } + + if (gEfiShellParametersProtocol->Argc < 4) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel1HiiHandle, L"for"); + return (SHELL_INVALID_PARAMETER); + } + + CurrentScriptFile = ShellCommandGetCurrentScriptFile(); + ASSERT(CurrentScriptFile != NULL); + + if ((CurrentScriptFile->CurrentCommand != NULL) && (CurrentScriptFile->CurrentCommand->Data == NULL)) { + FirstPass = TRUE; + + // + // Make sure that an End exists. + // + if (!MoveToTag(GetNextNode, L"endfor", L"for", NULL, CurrentScriptFile, TRUE, TRUE, FALSE)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_SYNTAX_NO_MATCHING), + gShellLevel1HiiHandle, + L"EndFor", + L"For", + CurrentScriptFile->CurrentCommand->Line); + return (SHELL_DEVICE_ERROR); + } + + // + // Process the line. + // + if (gEfiShellParametersProtocol->Argv[1][0] != L'%' || gEfiShellParametersProtocol->Argv[1][2] != CHAR_NULL + ||!((gEfiShellParametersProtocol->Argv[1][1] >= L'a' && gEfiShellParametersProtocol->Argv[1][1] <= L'z') + ||(gEfiShellParametersProtocol->Argv[1][1] >= L'A' && gEfiShellParametersProtocol->Argv[1][1] <= L'Z')) + ) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_VAR), gShellLevel1HiiHandle, gEfiShellParametersProtocol->Argv[1]); + return (SHELL_INVALID_PARAMETER); + } + + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + L"in", + gEfiShellParametersProtocol->Argv[2]) == 0) { + for (LoopVar = 0x3 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) { + ASSERT((ArgSet == NULL && ArgSize == 0) || (ArgSet != NULL)); + if (StrStr(gEfiShellParametersProtocol->Argv[LoopVar], L"*") != NULL + ||StrStr(gEfiShellParametersProtocol->Argv[LoopVar], L"?") != NULL + ||StrStr(gEfiShellParametersProtocol->Argv[LoopVar], L"[") != NULL + ||StrStr(gEfiShellParametersProtocol->Argv[LoopVar], L"]") != NULL) { + FileList = NULL; + Status = ShellOpenFileMetaArg ((CHAR16*)gEfiShellParametersProtocol->Argv[LoopVar], EFI_FILE_MODE_READ, &FileList); + if (EFI_ERROR(Status) || FileList == NULL || IsListEmpty(&FileList->Link)) { + ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L" \"", 0); + ArgSet = StrnCatGrow(&ArgSet, &ArgSize, gEfiShellParametersProtocol->Argv[LoopVar], 0); + ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L"\"", 0); + } else { + for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link) + ; !IsNull(&FileList->Link, &Node->Link) + ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link) + ){ + ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L" \"", 0); + ArgSet = StrnCatGrow(&ArgSet, &ArgSize, Node->FullName, 0); + ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L"\"", 0); + } + ShellCloseFileMetaArg(&FileList); + } + } else { + Parameter = gEfiShellParametersProtocol->Argv[LoopVar]; + if (Parameter[0] == L'\"' && Parameter[StrLen(Parameter)-1] == L'\"') { + ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L" ", 0); + ArgSet = StrnCatGrow(&ArgSet, &ArgSize, Parameter, 0); + } else { + ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L" \"", 0); + ArgSet = StrnCatGrow(&ArgSet, &ArgSize, Parameter, 0); + ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L"\"", 0); + } + } + } + if (ArgSet == NULL) { + ShellStatus = SHELL_OUT_OF_RESOURCES; + } else { + // + // set up for an 'in' for loop + // + NewSize = StrSize(ArgSet); + NewSize += sizeof(SHELL_FOR_INFO)+StrSize(gEfiShellParametersProtocol->Argv[1]); + Info = AllocateZeroPool(NewSize); + if (Info == NULL) { + FreePool (ArgSet); + return SHELL_OUT_OF_RESOURCES; + } + Info->Signature = SHELL_FOR_INFO_SIGNATURE; + CopyMem(Info->Set, ArgSet, StrSize(ArgSet)); + NewSize = StrSize(gEfiShellParametersProtocol->Argv[1]); + CopyMem(Info->Set+(StrSize(ArgSet)/sizeof(Info->Set[0])), gEfiShellParametersProtocol->Argv[1], NewSize); + Info->ReplacementName = Info->Set+StrSize(ArgSet)/sizeof(Info->Set[0]); + Info->CurrentValue = (CHAR16*)Info->Set; + Info->Step = 0; + Info->Current = 0; + Info->End = 0; + + if (InternalIsAliasOnList(Info->ReplacementName, &CurrentScriptFile->SubstList)) { + Info->RemoveSubstAlias = FALSE; + } else { + Info->RemoveSubstAlias = TRUE; + } + CurrentScriptFile->CurrentCommand->Data = Info; + } + } else if (gUnicodeCollation->StriColl( + gUnicodeCollation, + L"run", + gEfiShellParametersProtocol->Argv[2]) == 0) { + for (LoopVar = 0x3 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) { + ASSERT((ArgSet == NULL && ArgSize == 0) || (ArgSet != NULL)); + if (StrStr (gEfiShellParametersProtocol->Argv[LoopVar], L")") != NULL && + (LoopVar + 1) < gEfiShellParametersProtocol->Argc + ) { + return (SHELL_INVALID_PARAMETER); + } + if (ArgSet == NULL) { +// ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L"\"", 0); + } else { + ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L" ", 0); + } + ArgSet = StrnCatGrow(&ArgSet, &ArgSize, gEfiShellParametersProtocol->Argv[LoopVar], 0); +// ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L" ", 0); + } + if (ArgSet == NULL) { + ShellStatus = SHELL_OUT_OF_RESOURCES; + } else { + // + // set up for a 'run' for loop + // + Info = AllocateZeroPool(sizeof(SHELL_FOR_INFO)+StrSize(gEfiShellParametersProtocol->Argv[1])); + if (Info == NULL) { + FreePool (ArgSet); + return SHELL_OUT_OF_RESOURCES; + } + Info->Signature = SHELL_FOR_INFO_SIGNATURE; + CopyMem(Info->Set, gEfiShellParametersProtocol->Argv[1], StrSize(gEfiShellParametersProtocol->Argv[1])); + Info->ReplacementName = Info->Set; + Info->CurrentValue = NULL; + ArgSetWalker = ArgSet; + if (ArgSetWalker[0] != L'(') { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), + gShellLevel1HiiHandle, + ArgSet, + CurrentScriptFile->CurrentCommand->Line); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + TempSpot = StrStr(ArgSetWalker, L")"); + if (TempSpot != NULL) { + TempString = TempSpot+1; + if (*(TempString) != CHAR_NULL) { + while(TempString != NULL && *TempString == L' ') { + TempString++; + } + if (StrLen(TempString) > 0) { + TempSpot = NULL; + } + } + } + if (TempSpot == NULL) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), + gShellLevel1HiiHandle, + CurrentScriptFile->CurrentCommand->Line); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + *TempSpot = CHAR_NULL; + ArgSetWalker++; + while (ArgSetWalker != NULL && ArgSetWalker[0] == L' ') { + ArgSetWalker++; + } + if (!ShellIsValidForNumber(ArgSetWalker)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), + gShellLevel1HiiHandle, + ArgSet, + CurrentScriptFile->CurrentCommand->Line); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + if (ArgSetWalker[0] == L'-') { + Info->Current = 0 - (INTN)ReturnUintn(ArgSetWalker+1); + } else { + Info->Current = (INTN)ReturnUintn(ArgSetWalker); + } + ArgSetWalker = StrStr(ArgSetWalker, L" "); + while (ArgSetWalker != NULL && ArgSetWalker[0] == L' ') { + ArgSetWalker++; + } + if (ArgSetWalker == NULL || *ArgSetWalker == CHAR_NULL || !ShellIsValidForNumber(ArgSetWalker)){ + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), + gShellLevel1HiiHandle, + ArgSet, + CurrentScriptFile->CurrentCommand->Line); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + if (ArgSetWalker[0] == L'-') { + Info->End = 0 - (INTN)ReturnUintn(ArgSetWalker+1); + } else { + Info->End = (INTN)ReturnUintn(ArgSetWalker); + } + if (Info->Current < Info->End) { + Info->Step = 1; + } else { + Info->Step = -1; + } + + ArgSetWalker = StrStr(ArgSetWalker, L" "); + while (ArgSetWalker != NULL && ArgSetWalker[0] == L' ') { + ArgSetWalker++; + } + if (ArgSetWalker != NULL && *ArgSetWalker != CHAR_NULL) { + if (ArgSetWalker == NULL || *ArgSetWalker == CHAR_NULL || !ShellIsValidForNumber(ArgSetWalker)){ + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), + gShellLevel1HiiHandle, + ArgSet, + CurrentScriptFile->CurrentCommand->Line); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + if (*ArgSetWalker == L')') { + ASSERT(Info->Step == 1 || Info->Step == -1); + } else { + if (ArgSetWalker[0] == L'-') { + Info->Step = 0 - (INTN)ReturnUintn(ArgSetWalker+1); + } else { + Info->Step = (INTN)ReturnUintn(ArgSetWalker); + } + + if (StrStr(ArgSetWalker, L" ") != NULL) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), + gShellLevel1HiiHandle, + ArgSet, + CurrentScriptFile->CurrentCommand->Line); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } + } + + } + } + } + } + } + if (ShellStatus == SHELL_SUCCESS) { + if (InternalIsAliasOnList(Info->ReplacementName, &CurrentScriptFile->SubstList)) { + Info->RemoveSubstAlias = FALSE; + } else { + Info->RemoveSubstAlias = TRUE; + } + } + if (CurrentScriptFile->CurrentCommand != NULL) { + CurrentScriptFile->CurrentCommand->Data = Info; + } + } + } else { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), + gShellLevel1HiiHandle, + ArgSet, + CurrentScriptFile!=NULL + && CurrentScriptFile->CurrentCommand!=NULL + ? CurrentScriptFile->CurrentCommand->Line:0); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } else { + // + // These need to be NULL since they are used to determine if this is the first pass later on... + // + ASSERT(ArgSetWalker == NULL); + ASSERT(ArgSet == NULL); + } + + if (CurrentScriptFile != NULL && CurrentScriptFile->CurrentCommand != NULL) { + Info = (SHELL_FOR_INFO*)CurrentScriptFile->CurrentCommand->Data; + if (CurrentScriptFile->CurrentCommand->Reset) { + if (Info != NULL) { + Info->CurrentValue = (CHAR16*)Info->Set; + } + FirstPass = TRUE; + CurrentScriptFile->CurrentCommand->Reset = FALSE; + } + } else { + ShellStatus = SHELL_UNSUPPORTED; + Info = NULL; + } + if (ShellStatus == SHELL_SUCCESS) { + ASSERT(Info != NULL); + if (Info->Step != 0) { + // + // only advance if not the first pass + // + if (!FirstPass) { + // + // sequence version of for loop... + // + Info->Current += Info->Step; + } + + TempString = AllocateZeroPool(50*sizeof(CHAR16)); + UnicodeSPrint(TempString, 50*sizeof(CHAR16), L"%d", Info->Current); + InternalUpdateAliasOnList(Info->ReplacementName, TempString, &CurrentScriptFile->SubstList); + FreePool(TempString); + + if ((Info->Step > 0 && Info->Current > Info->End) || (Info->Step < 0 && Info->Current < Info->End)) { + CurrentScriptFile->CurrentCommand->Data = NULL; + // + // find the matching endfor (we're done with the loop) + // + if (!MoveToTag(GetNextNode, L"endfor", L"for", NULL, CurrentScriptFile, TRUE, FALSE, FALSE)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_SYNTAX_NO_MATCHING), + gShellLevel1HiiHandle, + L"EndFor", + L"For", + CurrentScriptFile!=NULL + && CurrentScriptFile->CurrentCommand!=NULL + ? CurrentScriptFile->CurrentCommand->Line:0); + ShellStatus = SHELL_DEVICE_ERROR; + } + if (Info->RemoveSubstAlias) { + // + // remove item from list + // + InternalRemoveAliasFromList(Info->ReplacementName, &CurrentScriptFile->SubstList); + } + FreePool(Info); + } + } else { + // + // Must be in 'in' version of for loop... + // + ASSERT(Info->Set != NULL); + if (Info->CurrentValue != NULL && *Info->CurrentValue != CHAR_NULL) { + if (Info->CurrentValue[0] == L' ') { + Info->CurrentValue++; + } + if (Info->CurrentValue[0] == L'\"') { + Info->CurrentValue++; + } + // + // do the next one of the set + // + ASSERT(TempString == NULL); + TempString = StrnCatGrow(&TempString, NULL, Info->CurrentValue, 0); + if (TempString == NULL) { + ShellStatus = SHELL_OUT_OF_RESOURCES; + } else { + TempSpot = StrStr(TempString, L"\" \""); + if (TempSpot != NULL) { + *TempSpot = CHAR_NULL; + } + while (TempString[StrLen(TempString)-1] == L'\"') { + TempString[StrLen(TempString)-1] = CHAR_NULL; + } + InternalUpdateAliasOnList(Info->ReplacementName, TempString, &CurrentScriptFile->SubstList); + Info->CurrentValue += StrLen(TempString); + + if (Info->CurrentValue[0] == L'\"') { + Info->CurrentValue++; + } + FreePool(TempString); + } + } else { + CurrentScriptFile->CurrentCommand->Data = NULL; + // + // find the matching endfor (we're done with the loop) + // + if (!MoveToTag(GetNextNode, L"endfor", L"for", NULL, CurrentScriptFile, TRUE, FALSE, FALSE)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_SYNTAX_NO_MATCHING), + gShellLevel1HiiHandle, + L"EndFor", + L"For", + CurrentScriptFile!=NULL + && CurrentScriptFile->CurrentCommand!=NULL + ? CurrentScriptFile->CurrentCommand->Line:0); + ShellStatus = SHELL_DEVICE_ERROR; + } + if (Info->RemoveSubstAlias) { + // + // remove item from list + // + InternalRemoveAliasFromList(Info->ReplacementName, &CurrentScriptFile->SubstList); + } + FreePool(Info); + } + } + } + if (ArgSet != NULL) { + FreePool(ArgSet); + } + return (ShellStatus); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/Goto.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/Goto.c new file mode 100644 index 00000000..5b7d78fb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/Goto.c @@ -0,0 +1,99 @@ +/** @file + Main file for goto shell level 1 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel1CommandsLib.h" + +/** + Function for 'goto' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunGoto ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CHAR16 *CompareString; + UINTN Size; + SCRIPT_FILE *CurrentScriptFile; + + ShellStatus = SHELL_SUCCESS; + CompareString = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + if (!gEfiShellProtocol->BatchIsActive()) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"Goto"); + return (SHELL_UNSUPPORTED); + } + + // + // parse the command line + // + Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel1HiiHandle, L"goto", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetRawValue(Package, 2) != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel1HiiHandle, L"goto"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetRawValue(Package, 1) == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel1HiiHandle, L"goto"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Size = 0; + ASSERT((CompareString == NULL && Size == 0) || (CompareString != NULL)); + CompareString = StrnCatGrow(&CompareString, &Size, L":", 0); + CompareString = StrnCatGrow(&CompareString, &Size, ShellCommandLineGetRawValue(Package, 1), 0); + // + // Check forwards and then backwards for a label... + // + if (!MoveToTag(GetNextNode, L"endfor", L"for", CompareString, ShellCommandGetCurrentScriptFile(), FALSE, FALSE, TRUE)) { + CurrentScriptFile = ShellCommandGetCurrentScriptFile(); + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_SYNTAX_NO_MATCHING), + gShellLevel1HiiHandle, + CompareString, + L"Goto", + CurrentScriptFile!=NULL + && CurrentScriptFile->CurrentCommand!=NULL + ? CurrentScriptFile->CurrentCommand->Line:0); + ShellStatus = SHELL_NOT_FOUND; + } + FreePool(CompareString); + } + ShellCommandLineFreeVarList (Package); + } + + return (ShellStatus); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/If.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/If.c new file mode 100644 index 00000000..02163bf4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/If.c @@ -0,0 +1,1105 @@ +/** @file + Main file for If and else shell level 1 function. + + (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel1CommandsLib.h" +#include + +typedef enum { + EndTagOr, + EndTagAnd, + EndTagThen, + EndTagMax +} END_TAG_TYPE; + +typedef enum { + OperatorGreaterThan, + OperatorLessThan, + OperatorEqual, + OperatorNotEqual, + OperatorGreatorOrEqual, + OperatorLessOrEqual, + OperatorUnisgnedGreaterThan, + OperatorUnsignedLessThan, + OperatorUnsignedGreaterOrEqual, + OperatorUnsignedLessOrEqual, + OperatorMax +} BIN_OPERATOR_TYPE; + +/** + Extract the next fragment, if there is one. + + @param[in, out] Statement The current remaining statement. + @param[in] Fragment The current fragment. + @param[out] Match TRUE when there is another Fragment in Statement, + FALSE otherwise. + + @retval EFI_SUCCESS The match operation is performed successfully. + @retval EFI_OUT_OF_RESOURCES Out of resources. +**/ +EFI_STATUS +IsNextFragment ( + IN OUT CONST CHAR16 **Statement, + IN CONST CHAR16 *Fragment, + OUT BOOLEAN *Match + ) +{ + CHAR16 *Tester; + + Tester = NULL; + + Tester = StrnCatGrow(&Tester, NULL, *Statement, StrLen(Fragment)); + if (Tester == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Tester[StrLen(Fragment)] = CHAR_NULL; + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)Fragment, + Tester) == 0) { + // + // increment the string pointer to the end of what we found and then chop off spaces... + // + *Statement+=StrLen(Fragment); + while (*Statement[0] == L' ') { + (*Statement)++; + } + *Match = TRUE; + } else { + *Match = FALSE; + } + FreePool(Tester); + return EFI_SUCCESS; +} + +/** + Determine if String represents a valid profile. + + @param[in] String The pointer to the string to test. + + @retval TRUE String is a valid profile. + @retval FALSE String is not a valid profile. +**/ +BOOLEAN +IsValidProfile ( + IN CONST CHAR16 *String + ) +{ + CONST CHAR16 *ProfilesString; + CONST CHAR16 *TempLocation; + + ProfilesString = ShellGetEnvironmentVariable(L"profiles"); + ASSERT(ProfilesString != NULL); + TempLocation = StrStr(ProfilesString, String); + if ((TempLocation != NULL) && (*(TempLocation-1) == L';') && (*(TempLocation+StrLen(String)) == L';')) { + return (TRUE); + } + return (FALSE); +} + +/** + Do a comparison between 2 things. + + @param[in] Compare1 The first item to compare. + @param[in] Compare2 The second item to compare. + @param[in] BinOp The type of comparison to perform. + @param[in] CaseInsensitive TRUE to do non-case comparison, FALSE otherwise. + @param[in] ForceStringCompare TRUE to force string comparison, FALSE otherwise. + + @return The result of the comparison. +**/ +BOOLEAN +TestOperation ( + IN CONST CHAR16 *Compare1, + IN CONST CHAR16 *Compare2, + IN CONST BIN_OPERATOR_TYPE BinOp, + IN CONST BOOLEAN CaseInsensitive, + IN CONST BOOLEAN ForceStringCompare + ) +{ + INTN Cmp1; + INTN Cmp2; + + // + // "Compare1 BinOp Compare2" + // + switch (BinOp) { + case OperatorUnisgnedGreaterThan: + case OperatorGreaterThan: + if (ForceStringCompare || !ShellIsHexOrDecimalNumber(Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber(Compare2, FALSE, FALSE)) { + // + // string compare + // + if ((CaseInsensitive && StringNoCaseCompare(&Compare1, &Compare2) > 0) || (StringCompare(&Compare1, &Compare2) > 0)) { + return (TRUE); + } + } else { + // + // numeric compare + // + if (Compare1[0] == L'-') { + Cmp1 = 0 - (INTN)ShellStrToUintn(Compare1+1); + } else { + Cmp1 = (INTN)ShellStrToUintn(Compare1); + } + if (Compare2[0] == L'-') { + Cmp2 = 0 - (INTN)ShellStrToUintn(Compare2+1); + } else { + Cmp2 = (INTN)ShellStrToUintn(Compare2); + } + if (BinOp == OperatorGreaterThan) { + if (Cmp1 > Cmp2) { + return (TRUE); + } + } else { + if ((UINTN)Cmp1 > (UINTN)Cmp2) { + return (TRUE); + } + } + } + return (FALSE); + case OperatorUnsignedLessThan: + case OperatorLessThan: + if (ForceStringCompare || !ShellIsHexOrDecimalNumber(Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber(Compare2, FALSE, FALSE)) { + // + // string compare + // + if ((CaseInsensitive && StringNoCaseCompare(&Compare1, &Compare2) < 0) || (StringCompare(&Compare1, &Compare2) < 0)) { + return (TRUE); + } + } else { + // + // numeric compare + // + if (Compare1[0] == L'-') { + Cmp1 = 0 - (INTN)ShellStrToUintn(Compare1+1); + } else { + Cmp1 = (INTN)ShellStrToUintn(Compare1); + } + if (Compare2[0] == L'-') { + Cmp2 = 0 - (INTN)ShellStrToUintn(Compare2+1); + } else { + Cmp2 = (INTN)ShellStrToUintn(Compare2); + } + if (BinOp == OperatorLessThan) { + if (Cmp1 < Cmp2) { + return (TRUE); + } + } else { + if ((UINTN)Cmp1 < (UINTN)Cmp2) { + return (TRUE); + } + } + + } + return (FALSE); + case OperatorEqual: + if (ForceStringCompare || !ShellIsHexOrDecimalNumber(Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber(Compare2, FALSE, FALSE)) { + // + // string compare + // + if ((CaseInsensitive && StringNoCaseCompare(&Compare1, &Compare2) == 0) || (StringCompare(&Compare1, &Compare2) == 0)) { + return (TRUE); + } + } else { + // + // numeric compare + // + if (Compare1[0] == L'-') { + Cmp1 = 0 - (INTN)ShellStrToUintn(Compare1+1); + } else { + Cmp1 = (INTN)ShellStrToUintn(Compare1); + } + if (Compare2[0] == L'-') { + Cmp2 = 0 - (INTN)ShellStrToUintn(Compare2+1); + } else { + Cmp2 = (INTN)ShellStrToUintn(Compare2); + } + if (Cmp1 == Cmp2) { + return (TRUE); + } + } + return (FALSE); + case OperatorNotEqual: + if (ForceStringCompare || !ShellIsHexOrDecimalNumber(Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber(Compare2, FALSE, FALSE)) { + // + // string compare + // + if ((CaseInsensitive && StringNoCaseCompare(&Compare1, &Compare2) != 0) || (StringCompare(&Compare1, &Compare2) != 0)) { + return (TRUE); + } + } else { + // + // numeric compare + // + if (Compare1[0] == L'-') { + Cmp1 = 0 - (INTN)ShellStrToUintn(Compare1+1); + } else { + Cmp1 = (INTN)ShellStrToUintn(Compare1); + } + if (Compare2[0] == L'-') { + Cmp2 = 0 - (INTN)ShellStrToUintn(Compare2+1); + } else { + Cmp2 = (INTN)ShellStrToUintn(Compare2); + } + if (Cmp1 != Cmp2) { + return (TRUE); + } + } + return (FALSE); + case OperatorUnsignedGreaterOrEqual: + case OperatorGreatorOrEqual: + if (ForceStringCompare || !ShellIsHexOrDecimalNumber(Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber(Compare2, FALSE, FALSE)) { + // + // string compare + // + if ((CaseInsensitive && StringNoCaseCompare(&Compare1, &Compare2) >= 0) || (StringCompare(&Compare1, &Compare2) >= 0)) { + return (TRUE); + } + } else { + // + // numeric compare + // + if (Compare1[0] == L'-') { + Cmp1 = 0 - (INTN)ShellStrToUintn(Compare1+1); + } else { + Cmp1 = (INTN)ShellStrToUintn(Compare1); + } + if (Compare2[0] == L'-') { + Cmp2 = 0 - (INTN)ShellStrToUintn(Compare2+1); + } else { + Cmp2 = (INTN)ShellStrToUintn(Compare2); + } + if (BinOp == OperatorGreatorOrEqual) { + if (Cmp1 >= Cmp2) { + return (TRUE); + } + } else { + if ((UINTN)Cmp1 >= (UINTN)Cmp2) { + return (TRUE); + } + } + } + return (FALSE); + case OperatorLessOrEqual: + case OperatorUnsignedLessOrEqual: + if (ForceStringCompare || !ShellIsHexOrDecimalNumber(Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber(Compare2, FALSE, FALSE)) { + // + // string compare + // + if ((CaseInsensitive && StringNoCaseCompare(&Compare1, &Compare2) <= 0) || (StringCompare(&Compare1, &Compare2) <= 0)) { + return (TRUE); + } + } else { + // + // numeric compare + // + if (Compare1[0] == L'-') { + Cmp1 = 0 - (INTN)ShellStrToUintn(Compare1+1); + } else { + Cmp1 = (INTN)ShellStrToUintn(Compare1); + } + if (Compare2[0] == L'-') { + Cmp2 = 0 - (INTN)ShellStrToUintn(Compare2+1); + } else { + Cmp2 = (INTN)ShellStrToUintn(Compare2); + } + if (BinOp == OperatorLessOrEqual) { + if (Cmp1 <= Cmp2) { + return (TRUE); + } + } else { + if ((UINTN)Cmp1 <= (UINTN)Cmp2) { + return (TRUE); + } + } + } + return (FALSE); + default: + ASSERT(FALSE); + return (FALSE); + } +} + +/** + Process an if statement and determine if its is valid or not. + + @param[in, out] PassingState Opon entry, the current state. Upon exit, + the new state. + @param[in] StartParameterNumber The number of the first parameter of + this statement. + @param[in] EndParameterNumber The number of the final parameter of + this statement. + @param[in] OperatorToUse The type of termination operator. + @param[in] CaseInsensitive TRUE for case insensitive, FALSE otherwise. + @param[in] ForceStringCompare TRUE for all string based, FALSE otherwise. + + @retval EFI_INVALID_PARAMETER A parameter was invalid. + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ProcessStatement ( + IN OUT BOOLEAN *PassingState, + IN UINTN StartParameterNumber, + IN UINTN EndParameterNumber, + IN CONST END_TAG_TYPE OperatorToUse, + IN CONST BOOLEAN CaseInsensitive, + IN CONST BOOLEAN ForceStringCompare + ) +{ + EFI_STATUS Status; + BOOLEAN OperationResult; + BOOLEAN NotPresent; + CHAR16 *StatementWalker; + BIN_OPERATOR_TYPE BinOp; + CHAR16 *Compare1; + CHAR16 *Compare2; + CHAR16 HexString[20]; + CHAR16 *TempSpot; + BOOLEAN Match; + + ASSERT((END_TAG_TYPE)OperatorToUse != EndTagThen); + + Status = EFI_SUCCESS; + BinOp = OperatorMax; + OperationResult = FALSE; + Match = FALSE; + StatementWalker = gEfiShellParametersProtocol->Argv[StartParameterNumber]; + if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"not", &Match)) && Match) { + NotPresent = TRUE; + StatementWalker = gEfiShellParametersProtocol->Argv[++StartParameterNumber]; + } else { + NotPresent = FALSE; + } + + // + // now check for 'boolfunc' operators + // + if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"isint", &Match)) && Match) { + if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match + && StatementWalker[StrLen(StatementWalker)-1] == L')') { + StatementWalker[StrLen(StatementWalker)-1] = CHAR_NULL; + OperationResult = ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE); + } else { + Status = EFI_INVALID_PARAMETER; + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"isint"); + } + } else if ((!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"exists", &Match)) && Match) || + (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"exist", &Match)) && Match)) { + if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match && + StatementWalker[StrLen(StatementWalker)-1] == L')') { + StatementWalker[StrLen(StatementWalker)-1] = CHAR_NULL; + // + // is what remains a file in CWD??? + // + OperationResult = (BOOLEAN)(ShellFileExists(StatementWalker)==EFI_SUCCESS); + } else if (StatementWalker[0] == CHAR_NULL && StartParameterNumber+1 == EndParameterNumber) { + OperationResult = (BOOLEAN)(ShellFileExists(gEfiShellParametersProtocol->Argv[++StartParameterNumber])==EFI_SUCCESS); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"exist(s)"); + Status = EFI_INVALID_PARAMETER; + } + } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"available", &Match)) && Match) { + if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match && + StatementWalker[StrLen(StatementWalker)-1] == L')') { + StatementWalker[StrLen(StatementWalker)-1] = CHAR_NULL; + // + // is what remains a file in the CWD or path??? + // + OperationResult = (BOOLEAN)(ShellIsFileInPath(StatementWalker)==EFI_SUCCESS); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"available"); + Status = EFI_INVALID_PARAMETER; + } + } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"profile", &Match)) && Match) { + if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match && + StatementWalker[StrLen(StatementWalker)-1] == L')') { + // + // Chop off that ')' + // + StatementWalker[StrLen(StatementWalker)-1] = CHAR_NULL; + OperationResult = IsValidProfile(StatementWalker); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"profile"); + Status = EFI_INVALID_PARAMETER; + } + } else if (StartParameterNumber+1 >= EndParameterNumber) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, gEfiShellParametersProtocol->Argv[StartParameterNumber]); + Status = EFI_INVALID_PARAMETER; + } else { + // + // must be 'item binop item' style + // + Compare1 = NULL; + Compare2 = NULL; + BinOp = OperatorMax; + + // + // get the first item + // + StatementWalker = gEfiShellParametersProtocol->Argv[StartParameterNumber]; + if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"efierror", &Match)) && Match) { + TempSpot = StrStr(StatementWalker, L")"); + if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match && TempSpot != NULL) { + *TempSpot = CHAR_NULL; + if (ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE)) { + UnicodeSPrint(HexString, sizeof(HexString), L"0x%x", ShellStrToUintn(StatementWalker)|MAX_BIT); + ASSERT(Compare1 == NULL); + Compare1 = StrnCatGrow(&Compare1, NULL, HexString, 0); + StatementWalker += StrLen(StatementWalker) + 1; + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"efierror"); + Status = EFI_INVALID_PARAMETER; + } + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"efierror"); + Status = EFI_INVALID_PARAMETER; + } + } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"pierror", &Match)) && Match) { + TempSpot = StrStr(StatementWalker, L")"); + if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match && TempSpot != NULL) { + *TempSpot = CHAR_NULL; + if (ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE)) { + UnicodeSPrint(HexString, sizeof(HexString), L"0x%x", ShellStrToUintn(StatementWalker)|MAX_BIT|(MAX_BIT>>2)); + ASSERT(Compare1 == NULL); + Compare1 = StrnCatGrow(&Compare1, NULL, HexString, 0); + StatementWalker += StrLen(StatementWalker) + 1; + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"pierror"); + Status = EFI_INVALID_PARAMETER; + } + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"pierror"); + Status = EFI_INVALID_PARAMETER; + } + } else if (!EFI_ERROR (IsNextFragment ((CONST CHAR16**)(&StatementWalker), L"oemerror", &Match)) && Match) { + TempSpot = StrStr(StatementWalker, L")"); + if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match && TempSpot != NULL) { + TempSpot = CHAR_NULL; + if (ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE)) { + UnicodeSPrint(HexString, sizeof(HexString), L"0x%x", ShellStrToUintn(StatementWalker)|MAX_BIT|(MAX_BIT>>1)); + ASSERT(Compare1 == NULL); + Compare1 = StrnCatGrow(&Compare1, NULL, HexString, 0); + StatementWalker += StrLen(StatementWalker) + 1; + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"oemerror"); + Status = EFI_INVALID_PARAMETER; + } + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"oemerror"); + Status = EFI_INVALID_PARAMETER; + } + } else { + ASSERT(Compare1 == NULL); + if (EndParameterNumber - StartParameterNumber > 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_STARTING), gShellLevel1HiiHandle, gEfiShellParametersProtocol->Argv[StartParameterNumber+2]); + Status = EFI_INVALID_PARAMETER; + } else { + // + // must be a raw string + // + Compare1 = StrnCatGrow(&Compare1, NULL, StatementWalker, 0); + } + } + + // + // get the operator + // + ASSERT(StartParameterNumber+1Argv[StartParameterNumber+1]; + if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"gt", &Match)) && Match) { + BinOp = OperatorGreaterThan; + } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"lt", &Match)) && Match) { + BinOp = OperatorLessThan; + } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"eq", &Match)) && Match) { + BinOp = OperatorEqual; + } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"ne", &Match)) && Match) { + BinOp = OperatorNotEqual; + } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"ge", &Match)) && Match) { + BinOp = OperatorGreatorOrEqual; + } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"le", &Match)) && Match) { + BinOp = OperatorLessOrEqual; + } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"==", &Match)) && Match) { + BinOp = OperatorEqual; + } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"ugt", &Match)) && Match) { + BinOp = OperatorUnisgnedGreaterThan; + } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"ult", &Match)) && Match) { + BinOp = OperatorUnsignedLessThan; + } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"uge", &Match)) && Match) { + BinOp = OperatorUnsignedGreaterOrEqual; + } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"ule", &Match)) && Match) { + BinOp = OperatorUnsignedLessOrEqual; + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_INVALID_BINOP), gShellLevel1HiiHandle, StatementWalker); + Status = EFI_INVALID_PARAMETER; + } + + // + // get the second item + // + ASSERT(StartParameterNumber+2<=EndParameterNumber); + StatementWalker = gEfiShellParametersProtocol->Argv[StartParameterNumber+2]; + if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"efierror", &Match)) && Match) { + TempSpot = StrStr(StatementWalker, L")"); + if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match && TempSpot != NULL) { + TempSpot = CHAR_NULL; + if (ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE)) { + UnicodeSPrint(HexString, sizeof(HexString), L"0x%x", ShellStrToUintn(StatementWalker)|MAX_BIT); + ASSERT(Compare2 == NULL); + Compare2 = StrnCatGrow(&Compare2, NULL, HexString, 0); + StatementWalker += StrLen(StatementWalker) + 1; + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"efierror"); + Status = EFI_INVALID_PARAMETER; + } + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"efierror"); + Status = EFI_INVALID_PARAMETER; + } + // + // can this be collapsed into the above? + // + } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"pierror", &Match)) && Match) { + TempSpot = StrStr(StatementWalker, L")"); + if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match && TempSpot != NULL) { + TempSpot = CHAR_NULL; + if (ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE)) { + UnicodeSPrint(HexString, sizeof(HexString), L"0x%x", ShellStrToUintn(StatementWalker)|MAX_BIT|(MAX_BIT>>2)); + ASSERT(Compare2 == NULL); + Compare2 = StrnCatGrow(&Compare2, NULL, HexString, 0); + StatementWalker += StrLen(StatementWalker) + 1; + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"pierror"); + Status = EFI_INVALID_PARAMETER; + } + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"pierror"); + Status = EFI_INVALID_PARAMETER; + } + } else if (!EFI_ERROR (IsNextFragment ((CONST CHAR16**)(&StatementWalker), L"oemerror", &Match)) && Match) { + TempSpot = StrStr(StatementWalker, L")"); + if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match && TempSpot != NULL) { + TempSpot = CHAR_NULL; + if (ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE)) { + UnicodeSPrint(HexString, sizeof(HexString), L"0x%x", ShellStrToUintn(StatementWalker)|MAX_BIT|(MAX_BIT>>1)); + ASSERT(Compare2 == NULL); + Compare2 = StrnCatGrow(&Compare2, NULL, HexString, 0); + StatementWalker += StrLen(StatementWalker) + 1; + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"oemerror"); + Status = EFI_INVALID_PARAMETER; + } + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"oemerror"); + Status = EFI_INVALID_PARAMETER; + } + } else { + // + // must be a raw string + // + ASSERT(Compare2 == NULL); + Compare2 = StrnCatGrow(&Compare2, NULL, StatementWalker, 0); + } + + if (Compare1 != NULL && Compare2 != NULL && BinOp != OperatorMax) { + OperationResult = TestOperation(Compare1, Compare2, BinOp, CaseInsensitive, ForceStringCompare); + } + + SHELL_FREE_NON_NULL(Compare1); + SHELL_FREE_NON_NULL(Compare2); + } + + // + // done processing do result... + // + + if (!EFI_ERROR(Status)) { + if (NotPresent) { + OperationResult = (BOOLEAN)(!OperationResult); + } + switch(OperatorToUse) { + case EndTagOr: + *PassingState = (BOOLEAN)(*PassingState || OperationResult); + break; + case EndTagAnd: + *PassingState = (BOOLEAN)(*PassingState && OperationResult); + break; + case EndTagMax: + *PassingState = (BOOLEAN)(OperationResult); + break; + default: + ASSERT(FALSE); + } + } + return (Status); +} + +/** + Break up the next part of the if statement (until the next 'and', 'or', or 'then'). + + @param[in] ParameterNumber The current parameter number. + @param[out] EndParameter Upon successful return, will point to the + parameter to start the next iteration with. + @param[out] EndTag Upon successful return, will point to the + type that was found at the end of this statement. + + @retval TRUE A valid statement was found. + @retval FALSE A valid statement was not found. +**/ +BOOLEAN +BuildNextStatement ( + IN UINTN ParameterNumber, + OUT UINTN *EndParameter, + OUT END_TAG_TYPE *EndTag + ) +{ + *EndTag = EndTagMax; + + for( + ; ParameterNumber < gEfiShellParametersProtocol->Argc + ; ParameterNumber++ + ) { + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + gEfiShellParametersProtocol->Argv[ParameterNumber], + L"or") == 0) { + *EndParameter = ParameterNumber - 1; + *EndTag = EndTagOr; + break; + } else if (gUnicodeCollation->StriColl( + gUnicodeCollation, + gEfiShellParametersProtocol->Argv[ParameterNumber], + L"and") == 0) { + *EndParameter = ParameterNumber - 1; + *EndTag = EndTagAnd; + break; + } else if (gUnicodeCollation->StriColl( + gUnicodeCollation, + gEfiShellParametersProtocol->Argv[ParameterNumber], + L"then") == 0) { + *EndParameter = ParameterNumber - 1; + *EndTag = EndTagThen; + break; + } + } + if (*EndTag == EndTagMax) { + return (FALSE); + } + return (TRUE); +} + +/** + Move the script file pointer to a different place in the script file. + This one is special since it handles the if/else/endif syntax. + + @param[in] ScriptFile The script file from GetCurrnetScriptFile(). + + @retval TRUE The move target was found and the move was successful. + @retval FALSE Something went wrong. +**/ +BOOLEAN +MoveToTagSpecial ( + IN SCRIPT_FILE *ScriptFile + ) +{ + SCRIPT_COMMAND_LIST *CommandNode; + BOOLEAN Found; + UINTN TargetCount; + CHAR16 *CommandName; + CHAR16 *CommandWalker; + CHAR16 *TempLocation; + + TargetCount = 1; + Found = FALSE; + + if (ScriptFile == NULL) { + return FALSE; + } + + for (CommandNode = (SCRIPT_COMMAND_LIST *)GetNextNode(&ScriptFile->CommandList, &ScriptFile->CurrentCommand->Link), Found = FALSE + ; !IsNull(&ScriptFile->CommandList, &CommandNode->Link) && !Found + ; CommandNode = (SCRIPT_COMMAND_LIST *)GetNextNode(&ScriptFile->CommandList, &CommandNode->Link) + ){ + + // + // get just the first part of the command line... + // + CommandName = NULL; + CommandName = StrnCatGrow(&CommandName, NULL, CommandNode->Cl, 0); + if (CommandName == NULL) { + continue; + } + CommandWalker = CommandName; + + // + // Skip leading spaces and tabs. + // + while ((CommandWalker[0] == L' ') || (CommandWalker[0] == L'\t')) { + CommandWalker++; + } + TempLocation = StrStr(CommandWalker, L" "); + + if (TempLocation != NULL) { + *TempLocation = CHAR_NULL; + } + + // + // did we find a nested item ? + // + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)CommandWalker, + L"If") == 0) { + TargetCount++; + } else if (TargetCount == 1 && gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)CommandWalker, + (CHAR16*)L"else") == 0) { + // + // else can only decrement the last part... not an nested if + // hence the TargetCount compare added + // + TargetCount--; + } else if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)CommandWalker, + (CHAR16*)L"endif") == 0) { + TargetCount--; + } + if (TargetCount == 0) { + ScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetNextNode(&ScriptFile->CommandList, &CommandNode->Link); + Found = TRUE; + } + + // + // Free the memory for this loop... + // + SHELL_FREE_NON_NULL(CommandName); + } + return (Found); +} + +/** + Deal with the result of the if operation. + + @param[in] Result The result of the if. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_NOT_FOUND The ending tag could not be found. +**/ +EFI_STATUS +PerformResultOperation ( + IN CONST BOOLEAN Result + ) +{ + if (Result || MoveToTagSpecial(ShellCommandGetCurrentScriptFile())) { + return (EFI_SUCCESS); + } + return (EFI_NOT_FOUND); +} + +/** + Function for 'if' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunIf ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + BOOLEAN CaseInsensitive; + BOOLEAN ForceString; + UINTN CurrentParameter; + UINTN EndParameter; + BOOLEAN CurrentValue; + END_TAG_TYPE Ending; + END_TAG_TYPE PreviousEnding; + SCRIPT_FILE *CurrentScriptFile; + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + if (!gEfiShellProtocol->BatchIsActive()) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"if"); + return (SHELL_UNSUPPORTED); + } + + if (gEfiShellParametersProtocol->Argc < 3) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel1HiiHandle, L"if"); + return (SHELL_INVALID_PARAMETER); + } + + // + // Make sure that an End exists. + // + CurrentScriptFile = ShellCommandGetCurrentScriptFile(); + if (!MoveToTag(GetNextNode, L"endif", L"if", NULL, CurrentScriptFile, TRUE, TRUE, FALSE)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_SYNTAX_NO_MATCHING), + gShellLevel1HiiHandle, + L"EndIf", + L"If", + CurrentScriptFile!=NULL + && CurrentScriptFile->CurrentCommand!=NULL + ? CurrentScriptFile->CurrentCommand->Line:0); + return (SHELL_DEVICE_ERROR); + } + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + CurrentParameter = 1; + EndParameter = 0; + + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + gEfiShellParametersProtocol->Argv[1], + L"/i") == 0 || + gUnicodeCollation->StriColl( + gUnicodeCollation, + gEfiShellParametersProtocol->Argv[2], + L"/i") == 0 || + (gEfiShellParametersProtocol->Argc > 3 && gUnicodeCollation->StriColl( + gUnicodeCollation, + gEfiShellParametersProtocol->Argv[3], + L"/i") == 0)) { + CaseInsensitive = TRUE; + CurrentParameter++; + } else { + CaseInsensitive = FALSE; + } + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + gEfiShellParametersProtocol->Argv[1], + L"/s") == 0 || + gUnicodeCollation->StriColl( + gUnicodeCollation, + gEfiShellParametersProtocol->Argv[2], + L"/s") == 0 || + (gEfiShellParametersProtocol->Argc > 3 && gUnicodeCollation->StriColl( + gUnicodeCollation, + gEfiShellParametersProtocol->Argv[3], + L"/s") == 0)) { + ForceString = TRUE; + CurrentParameter++; + } else { + ForceString = FALSE; + } + + for ( ShellStatus = SHELL_SUCCESS, CurrentValue = FALSE, Ending = EndTagMax + ; CurrentParameter < gEfiShellParametersProtocol->Argc && ShellStatus == SHELL_SUCCESS + ; CurrentParameter++) { + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + gEfiShellParametersProtocol->Argv[CurrentParameter], + L"then") == 0) { + // + // we are at the then + // + if (CurrentParameter+1 != gEfiShellParametersProtocol->Argc) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_TEXT_AFTER_THEN), gShellLevel1HiiHandle, L"if"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = PerformResultOperation(CurrentValue); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_AFTER_BAD), gShellLevel1HiiHandle, L"if", gEfiShellParametersProtocol->Argv[CurrentParameter]); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } + } else { + PreviousEnding = Ending; + // + // build up the next statement for analysis + // + if (!BuildNextStatement(CurrentParameter, &EndParameter, &Ending)) { + CurrentScriptFile = ShellCommandGetCurrentScriptFile(); + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_SYNTAX_NO_MATCHING), + gShellLevel1HiiHandle, + L"Then", + L"If", + CurrentScriptFile!=NULL + && CurrentScriptFile->CurrentCommand!=NULL + ? CurrentScriptFile->CurrentCommand->Line:0); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // Analyze the statement + // + Status = ProcessStatement(&CurrentValue, CurrentParameter, EndParameter, PreviousEnding, CaseInsensitive, ForceString); + if (EFI_ERROR(Status)) { +// ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_STARTING), gShellLevel1HiiHandle, gEfiShellParametersProtocol->Argv[CurrentParameter]); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // Optomize to get out of the loop early... + // + if ((Ending == EndTagOr && CurrentValue) || (Ending == EndTagAnd && !CurrentValue)) { + Status = PerformResultOperation(CurrentValue); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_AFTER_BAD), gShellLevel1HiiHandle, L"if", gEfiShellParametersProtocol->Argv[CurrentParameter]); + ShellStatus = SHELL_INVALID_PARAMETER; + } + break; + } + } + } + if (ShellStatus == SHELL_SUCCESS){ + CurrentParameter = EndParameter; + // + // Skip over the or or and parameter. + // + if (Ending == EndTagOr || Ending == EndTagAnd) { + CurrentParameter++; + } + } + } + } + return (ShellStatus); +} + +/** + Function for 'else' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunElse ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + SCRIPT_FILE *CurrentScriptFile; + + Status = CommandInit (); + ASSERT_EFI_ERROR (Status); + + if (gEfiShellParametersProtocol->Argc > 1) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel1HiiHandle, L"if"); + return (SHELL_INVALID_PARAMETER); + } + + if (!gEfiShellProtocol->BatchIsActive()) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"Else"); + return (SHELL_UNSUPPORTED); + } + + CurrentScriptFile = ShellCommandGetCurrentScriptFile(); + + if (!MoveToTag(GetPreviousNode, L"if", L"endif", NULL, CurrentScriptFile, FALSE, TRUE, FALSE)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_SYNTAX_NO_MATCHING), + gShellLevel1HiiHandle, + L"If", + L"Else", + CurrentScriptFile!=NULL + && CurrentScriptFile->CurrentCommand!=NULL + ? CurrentScriptFile->CurrentCommand->Line:0); + return (SHELL_DEVICE_ERROR); + } + if (!MoveToTag(GetPreviousNode, L"if", L"else", NULL, CurrentScriptFile, FALSE, TRUE, FALSE)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_SYNTAX_NO_MATCHING), + gShellLevel1HiiHandle, + L"If", + L"Else", + CurrentScriptFile!=NULL + && CurrentScriptFile->CurrentCommand!=NULL + ? CurrentScriptFile->CurrentCommand->Line:0); + return (SHELL_DEVICE_ERROR); + } + + if (!MoveToTag(GetNextNode, L"endif", L"if", NULL, CurrentScriptFile, FALSE, FALSE, FALSE)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_SYNTAX_NO_MATCHING), + gShellLevel1HiiHandle, + L"EndIf", + "Else", + CurrentScriptFile!=NULL + && CurrentScriptFile->CurrentCommand!=NULL + ? CurrentScriptFile->CurrentCommand->Line:0); + return (SHELL_DEVICE_ERROR); + } + + return (SHELL_SUCCESS); +} + +/** + Function for 'endif' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunEndIf ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + SCRIPT_FILE *CurrentScriptFile; + + Status = CommandInit (); + ASSERT_EFI_ERROR (Status); + + if (gEfiShellParametersProtocol->Argc > 1) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel1HiiHandle, L"if"); + return (SHELL_INVALID_PARAMETER); + } + + if (!gEfiShellProtocol->BatchIsActive()) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"Endif"); + return (SHELL_UNSUPPORTED); + } + + CurrentScriptFile = ShellCommandGetCurrentScriptFile(); + if (!MoveToTag(GetPreviousNode, L"if", L"endif", NULL, CurrentScriptFile, FALSE, TRUE, FALSE)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_SYNTAX_NO_MATCHING), + gShellLevel1HiiHandle, + L"If", + L"EndIf", + CurrentScriptFile!=NULL + && CurrentScriptFile->CurrentCommand!=NULL + ? CurrentScriptFile->CurrentCommand->Line:0); + return (SHELL_DEVICE_ERROR); + } + + return (SHELL_SUCCESS); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/Shift.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/Shift.c new file mode 100644 index 00000000..ad6ac0a7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/Shift.c @@ -0,0 +1,58 @@ +/** @file + Main file for Shift shell level 1 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel1CommandsLib.h" + +/** + Function for 'shift' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunShift ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + SCRIPT_FILE *CurrentScriptFile; + UINTN LoopVar; + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + if (!gEfiShellProtocol->BatchIsActive()) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"shift"); + return (SHELL_UNSUPPORTED); + } + + CurrentScriptFile = ShellCommandGetCurrentScriptFile(); + ASSERT(CurrentScriptFile != NULL); + + if (CurrentScriptFile->Argc < 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel1HiiHandle, L"shift"); + return (SHELL_UNSUPPORTED); + } + + for (LoopVar = 0 ; LoopVar < CurrentScriptFile->Argc ; LoopVar++) { + if (LoopVar == 0) { + SHELL_FREE_NON_NULL(CurrentScriptFile->Argv[LoopVar]); + } + if (LoopVar < CurrentScriptFile->Argc -1) { + CurrentScriptFile->Argv[LoopVar] = CurrentScriptFile->Argv[LoopVar+1]; + } else { + CurrentScriptFile->Argv[LoopVar] = NULL; + } + } + CurrentScriptFile->Argc--; + return (SHELL_SUCCESS); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/Stall.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/Stall.c new file mode 100644 index 00000000..eb20693e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/Stall.c @@ -0,0 +1,78 @@ +/** @file + Main file for stall shell level 1 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel1CommandsLib.h" + +/** + Function for 'stall' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunStall ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + UINT64 Intermediate; + + ShellStatus = SHELL_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel1HiiHandle, L"stall", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetRawValue(Package, 2) != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel1HiiHandle, L"stall"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetRawValue(Package, 1) == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel1HiiHandle, L"stall"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = ShellConvertStringToUint64(ShellCommandLineGetRawValue(Package, 1), &Intermediate, FALSE, FALSE); + if (EFI_ERROR(Status) || ((UINT64)(UINTN)(Intermediate)) != Intermediate) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel1HiiHandle, L"stall", ShellCommandLineGetRawValue(Package, 1)); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = gBS->Stall((UINTN)Intermediate); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_STALL_FAILED), gShellLevel1HiiHandle, L"stall"); + ShellStatus = SHELL_DEVICE_ERROR; + } + } + } + ShellCommandLineFreeVarList (Package); + } + return (ShellStatus); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.c new file mode 100644 index 00000000..2ce0b560 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.c @@ -0,0 +1,302 @@ +/** @file + Main file for NULL named library for level 1 shell command functions. + + (C) Copyright 2013 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel1CommandsLib.h" + +STATIC CONST CHAR16 mFileName[] = L"ShellCommands"; +EFI_HII_HANDLE gShellLevel1HiiHandle = NULL; + +/** + Return the help text filename. Only used if no HII information found. + + @retval the filename. +**/ +CONST CHAR16* +EFIAPI +ShellCommandGetManFileNameLevel1 ( + VOID + ) +{ + return (mFileName); +} + +/** + Constructor for the Shell Level 1 Commands library. + + Install the handlers for level 1 UEFI Shell 2.0 commands. + + @param ImageHandle the image handle of the process + @param SystemTable the EFI System Table pointer + + @retval EFI_SUCCESS the shell command handlers were installed sucessfully + @retval EFI_UNSUPPORTED the shell level required was not found. +**/ +EFI_STATUS +EFIAPI +ShellLevel1CommandsLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + // + // if shell level is less than 2 do nothing + // + if (PcdGet8(PcdShellSupportLevel) < 1) { + return (EFI_SUCCESS); + } + + gShellLevel1HiiHandle = HiiAddPackages (&gShellLevel1HiiGuid, gImageHandle, UefiShellLevel1CommandsLibStrings, NULL); + if (gShellLevel1HiiHandle == NULL) { + return (EFI_DEVICE_ERROR); + } + + // + // install our shell command handlers that are always installed + // + ShellCommandRegisterCommandName(L"stall", ShellCommandRunStall , ShellCommandGetManFileNameLevel1, 1, L"", FALSE, gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8(PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN(STR_GET_HELP_STALL) )); + ShellCommandRegisterCommandName(L"for", ShellCommandRunFor , ShellCommandGetManFileNameLevel1, 1, L"", FALSE, gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8(PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN(STR_GET_HELP_FOR) )); + ShellCommandRegisterCommandName(L"goto", ShellCommandRunGoto , ShellCommandGetManFileNameLevel1, 1, L"", FALSE, gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8(PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN(STR_GET_HELP_GOTO) )); + ShellCommandRegisterCommandName(L"if", ShellCommandRunIf , ShellCommandGetManFileNameLevel1, 1, L"", FALSE, gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8(PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN(STR_GET_HELP_IF) )); + ShellCommandRegisterCommandName(L"shift", ShellCommandRunShift , ShellCommandGetManFileNameLevel1, 1, L"", FALSE, gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8(PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN(STR_GET_HELP_SHIFT) )); + ShellCommandRegisterCommandName(L"exit", ShellCommandRunExit , ShellCommandGetManFileNameLevel1, 1, L"", TRUE , gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8(PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN(STR_GET_HELP_EXIT) )); + ShellCommandRegisterCommandName(L"else", ShellCommandRunElse , ShellCommandGetManFileNameLevel1, 1, L"", FALSE, gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8(PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN(STR_GET_HELP_ELSE) )); + ShellCommandRegisterCommandName(L"endif", ShellCommandRunEndIf , ShellCommandGetManFileNameLevel1, 1, L"", FALSE, gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8(PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN(STR_GET_HELP_ENDIF) )); + ShellCommandRegisterCommandName(L"endfor", ShellCommandRunEndFor , ShellCommandGetManFileNameLevel1, 1, L"", FALSE, gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8(PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN(STR_GET_HELP_ENDFOR))); + + return (EFI_SUCCESS); +} + +/** + Destructor for the library. free any resources. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. +**/ +EFI_STATUS +EFIAPI +ShellLevel1CommandsLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + if (gShellLevel1HiiHandle != NULL) { + HiiRemovePackages(gShellLevel1HiiHandle); + } + return (EFI_SUCCESS); +} + +/** + Test a node to see if meets the criterion. + + It functions so that count starts at 1 and it increases or decreases when it + hits the specified tags. when it hits zero the location has been found. + + DecrementerTag and IncrementerTag are used to get around for/endfor and + similar paired types where the entire middle should be ignored. + + If label is used it will be used instead of the count. + + @param[in] Function The function to use to enumerate through the + list. Normally GetNextNode or GetPreviousNode. + @param[in] DecrementerTag The tag to decrement the count at. + @param[in] IncrementerTag The tag to increment the count at. + @param[in] Label A label to look for. + @param[in, out] ScriptFile The pointer to the current script file structure. + @param[in] MovePast TRUE makes function return 1 past the found + location. + @param[in] FindOnly TRUE to not change the ScriptFile. + @param[in] CommandNode The pointer to the Node to test. + @param[in, out] TargetCount The pointer to the current count. +**/ +BOOLEAN +TestNodeForMove ( + IN CONST LIST_MANIP_FUNC Function, + IN CONST CHAR16 *DecrementerTag, + IN CONST CHAR16 *IncrementerTag, + IN CONST CHAR16 *Label OPTIONAL, + IN OUT SCRIPT_FILE *ScriptFile, + IN CONST BOOLEAN MovePast, + IN CONST BOOLEAN FindOnly, + IN CONST SCRIPT_COMMAND_LIST *CommandNode, + IN OUT UINTN *TargetCount + ) +{ + BOOLEAN Found; + CHAR16 *CommandName; + CHAR16 *CommandNameWalker; + CHAR16 *TempLocation; + + Found = FALSE; + + // + // get just the first part of the command line... + // + CommandName = NULL; + CommandName = StrnCatGrow(&CommandName, NULL, CommandNode->Cl, 0); + if (CommandName == NULL) { + return (FALSE); + } + + CommandNameWalker = CommandName; + + // + // Skip leading spaces and tabs. + // + while ((CommandNameWalker[0] == L' ') || (CommandNameWalker[0] == L'\t')) { + CommandNameWalker++; + } + TempLocation = StrStr(CommandNameWalker, L" "); + + if (TempLocation != NULL) { + *TempLocation = CHAR_NULL; + } + + // + // did we find a nested item ? + // + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)CommandNameWalker, + (CHAR16*)IncrementerTag) == 0) { + (*TargetCount)++; + } else if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)CommandNameWalker, + (CHAR16*)DecrementerTag) == 0) { + if (*TargetCount > 0) { + (*TargetCount)--; + } + } + + // + // did we find the matching one... + // + if (Label == NULL) { + if (*TargetCount == 0) { + Found = TRUE; + if (!FindOnly) { + if (MovePast) { + ScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)(*Function)(&ScriptFile->CommandList, &CommandNode->Link); + } else { + ScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)CommandNode; + } + } + } + } else { + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)CommandNameWalker, + (CHAR16*)Label) == 0 + && (*TargetCount) == 0) { + Found = TRUE; + if (!FindOnly) { + // + // we found the target label without loops + // + if (MovePast) { + ScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)(*Function)(&ScriptFile->CommandList, &CommandNode->Link); + } else { + ScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)CommandNode; + } + } + } + } + + // + // Free the memory for this loop... + // + FreePool(CommandName); + return (Found); +} + +/** + Move the script pointer from 1 tag (line) to another. + + It functions so that count starts at 1 and it increases or decreases when it + hits the specified tags. when it hits zero the location has been found. + + DecrementerTag and IncrementerTag are used to get around for/endfor and + similar paired types where the entire middle should be ignored. + + If label is used it will be used instead of the count. + + @param[in] Function The function to use to enumerate through the + list. Normally GetNextNode or GetPreviousNode. + @param[in] DecrementerTag The tag to decrement the count at. + @param[in] IncrementerTag The tag to increment the count at. + @param[in] Label A label to look for. + @param[in, out] ScriptFile The pointer to the current script file structure. + @param[in] MovePast TRUE makes function return 1 past the found + location. + @param[in] FindOnly TRUE to not change the ScriptFile. + @param[in] WrapAroundScript TRUE to wrap end-to-begining or vise versa in + searching. +**/ +BOOLEAN +MoveToTag ( + IN CONST LIST_MANIP_FUNC Function, + IN CONST CHAR16 *DecrementerTag, + IN CONST CHAR16 *IncrementerTag, + IN CONST CHAR16 *Label OPTIONAL, + IN OUT SCRIPT_FILE *ScriptFile, + IN CONST BOOLEAN MovePast, + IN CONST BOOLEAN FindOnly, + IN CONST BOOLEAN WrapAroundScript + ) +{ + SCRIPT_COMMAND_LIST *CommandNode; + BOOLEAN Found; + UINTN TargetCount; + + if (Label == NULL) { + TargetCount = 1; + } else { + TargetCount = 0; + } + + if (ScriptFile == NULL) { + return FALSE; + } + + for (CommandNode = (SCRIPT_COMMAND_LIST *)(*Function)(&ScriptFile->CommandList, &ScriptFile->CurrentCommand->Link), Found = FALSE + ; !IsNull(&ScriptFile->CommandList, &CommandNode->Link)&& !Found + ; CommandNode = (SCRIPT_COMMAND_LIST *)(*Function)(&ScriptFile->CommandList, &CommandNode->Link) + ){ + Found = TestNodeForMove( + Function, + DecrementerTag, + IncrementerTag, + Label, + ScriptFile, + MovePast, + FindOnly, + CommandNode, + &TargetCount); + } + + if (WrapAroundScript && !Found) { + for (CommandNode = (SCRIPT_COMMAND_LIST *)GetFirstNode(&ScriptFile->CommandList), Found = FALSE + ; CommandNode != ScriptFile->CurrentCommand && !Found + ; CommandNode = (SCRIPT_COMMAND_LIST *)(*Function)(&ScriptFile->CommandList, &CommandNode->Link) + ){ + Found = TestNodeForMove( + Function, + DecrementerTag, + IncrementerTag, + Label, + ScriptFile, + MovePast, + FindOnly, + CommandNode, + &TargetCount); + } + } + return (Found); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.h new file mode 100644 index 00000000..6e1b55b2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.h @@ -0,0 +1,203 @@ +/** @file + Main file for NULL named library for level 1 shell command functions. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _UEFI_SHELL_LEVEL1_COMMANDS_LIB_H_ +#define _UEFI_SHELL_LEVEL1_COMMANDS_LIB_H_ + +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern EFI_HII_HANDLE gShellLevel1HiiHandle; + +/** + Function for 'stall' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunStall ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'exit' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunExit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'endif' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunEndIf ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'for' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunFor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'endfor' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunEndFor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'if' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunIf ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'goto' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunGoto ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'shift' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunShift ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + + +/** + Function for 'else' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunElse ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/// +/// Function prototype for BOTH GetNextNode and GetPreviousNode... +/// This is used to control the MoveToTag function direction... +/// +typedef +LIST_ENTRY * +(EFIAPI *LIST_MANIP_FUNC)( + IN CONST LIST_ENTRY *List, + IN CONST LIST_ENTRY *Node + ); + +/** + Move the script pointer from 1 tag (line) to another. + + It functions so that count starts at 1 and it increases or decreases when it + hits the specified tags. when it hits zero the location has been found. + + DecrementerTag and IncrementerTag are used to get around for/endfor and + similar paired types where the entire middle should be ignored. + + If label is used it will be used instead of the count. + + @param[in] Function The function to use to enumerate through the + list. Normally GetNextNode or GetPreviousNode. + @param[in] DecrementerTag The tag to decrement the count at. + @param[in] IncrementerTag The tag to increment the count at. + @param[in] Label A label to look for. + @param[in, out] ScriptFile The pointer to the current script file structure. + @param[in] MovePast TRUE makes function return 1 past the found + location. + @param[in] FindOnly TRUE to not change the ScriptFile. + @param[in] WrapAroundScript TRUE to wrap end-to-begining or vise versa in + searching. +**/ +BOOLEAN +MoveToTag ( + IN CONST LIST_MANIP_FUNC Function, + IN CONST CHAR16 *DecrementerTag, + IN CONST CHAR16 *IncrementerTag, + IN CONST CHAR16 *Label OPTIONAL, + IN OUT SCRIPT_FILE *ScriptFile, + IN CONST BOOLEAN MovePast, + IN CONST BOOLEAN FindOnly, + IN CONST BOOLEAN WrapAroundScript + ); + +#endif + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf new file mode 100644 index 00000000..fee56574 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf @@ -0,0 +1,53 @@ +## @file +# Provides shell level 1 functions +# +# Copyright (c) 2009-2015, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiShellLevel1CommandsLib + FILE_GUID = 50cb6037-1102-47af-b2dd-9944b6eb1abe + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = ShellLevel1CommandsLibConstructor + DESTRUCTOR = ShellLevel1CommandsLibDestructor + +[Sources.common] + UefiShellLevel1CommandsLib.c + UefiShellLevel1CommandsLib.h + UefiShellLevel1CommandsLib.uni + Exit.c + Goto.c + If.c + For.c + Shift.c + Stall.c + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + ShellCommandLib + ShellLib + UefiLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + SortLib + PrintLib + +[Pcd.common] + gEfiShellPkgTokenSpaceGuid.PcdShellSupportLevel ## CONSUMES + +[Guids] + gShellLevel1HiiGuid ## SOMETIMES_CONSUMES ## HII diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.uni b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.uni new file mode 100644 index 00000000..cd4c6cb7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.uni @@ -0,0 +1,498 @@ +// /** +// +// (C) Copyright 2014-2015 Hewlett-Packard Development Company, L.P.
+// Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// Module Name: +// +// UefiShellLevel2CommandsLib.uni +// +// Abstract: +// +// String definitions for UEFI Shell 2.0 level 1 commands +// +// +// **/ + +/=# + +#langdef en-US "english" + +#string STR_NO_SCRIPT #language en-US "The command '%H%s%N' is incorrect outside of a script\r\n" +#string STR_GEN_PROBLEM #language en-US "%H%s%N: Unknown flag - '%H%s%N'\r\n" +#string STR_GEN_PROBLEM_VAL #language en-US "%H%s%N: Bad value - '%H%s%N' for flag - '%H%s%N'\r\n" +#string STR_GEN_PROBLEM_SCRIPT #language en-US "The argument '%B%s%N' is incorrect. Line: %d\r\n" +#string STR_GEN_INV_VAR #language en-US "The script's Indexvar '%B%s%N' is incorrect\r\n" +#string STR_GEN_TOO_FEW #language en-US "%H%s%N: Too few arguments\r\n" +#string STR_GEN_TOO_MANY #language en-US "%H%s%N: Too many arguments\r\n" +#string STR_GEN_PARAM_INV #language en-US "%H%s%N: Invalid argument - '%H%s%N'\r\n" + +#string STR_TEXT_AFTER_THEN #language en-US "%H%s%N: Then cannot be followed by anything\r\n" +#string STR_SYNTAX_AFTER_BAD #language en-US "%H%s%N: Syntax after '%H%s%N' is incorrect\r\n" +#string STR_SYNTAX_IN #language en-US "Syntax after analyzing %s\r\n" +#string STR_SYNTAX_NO_MATCHING #language en-US "No matching '%H%s%N' for '%H%s%N' statement found. Line: %d\r\n" +#string STR_INVALID_BINOP #language en-US "Binary operator not found first in '%H%s%N'\r\n" +#string STR_SYNTAX_STARTING #language en-US "Syntax after %s\r\n" + +#string STR_STALL_FAILED #language en-US "%H%s%N: BootService Stall() failed\r\n" + +#string STR_GET_HELP_EXIT #language en-US "" +".TH exit 0 "exits the script or shell"\r\n" +".SH NAME\r\n" +"Exits the UEFI Shell or the current script.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"EXIT [/b] [exit-code]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" /b - Indicates that only the current UEFI shell script should be\r\n" +" terminated. Ignored if not used within a script.\r\n" +" exit-code - If exiting a UEFI shell script, the value that will be placed\r\n" +" into the environment variable lasterror. If exiting an instance\r\n" +" of the UEFI shell, the value that will be returned to the\r\n" +" caller. If not specified, then 0 will be returned.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command exits the UEFI Shell or, if /b is specified, the current\r\n" +" script.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To exit shell successfully:\r\n" +" Shell> exit\r\n" +" \r\n" +" * To exit the current UEFI shell script:\r\n" +" Shell> exit /b \r\n" +" \r\n" +" * To exit a UEFI shell script with exit-code value returned to the caller:\r\n" +" Shell> exit 0\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" 0 Exited normally\r\n" +" exit-code The return value specified as an option.\r\n" + +#string STR_GET_HELP_FOR #language en-US "" +".TH for 0 "starts a for loop"\r\n" +".SH NAME\r\n" +"Starts a loop based on 'for' syntax.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"FOR %indexvar IN set\r\n" +" command [arguments]\r\n" +" [command [arguments]]\r\n" +" ...\r\n" +"ENDFOR\r\n" +" \r\n" +"FOR %indexvar RUN (start end [step])\r\n" +" command [arguments]\r\n" +" [command [arguments]]\r\n" +" ...\r\n" +"ENDFOR\r\n" +".SH OPTIONS\r\n" +" \r\n" +" %indexvar - Variable name used to index a set\r\n" +" set - Set to be searched\r\n" +" command [arguments] - Command to be executed with optional arguments\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. The FOR command executes one or more commands for each item in a set of\r\n" +" items. The set may be text strings or filenames or a mixture of both,\r\n" +" separated by spaces (if not in a quotation).\r\n" +" 2. If the length of an element in the set is between 0 and 256, and if the\r\n" +" string contains wildcards, the string will be treated as a file name\r\n" +" containing wildcards, and be expanded before command is executed.\r\n" +" 3. If after expansion no such files are found, the literal string itself is\r\n" +" kept. %indexvar is any alphabet character from 'a' to 'z' or 'A' to 'Z',\r\n" +" and they are case sensitive. It should not be a digit (0-9) because\r\n" +" %digit will be interpreted as a positional argument on the command line\r\n" +" that launches the script. The namespace for index variables is separate\r\n" +" from that for environment variables, so if %indexvar has the same name as\r\n" +" an existing environment variable, the environment variable will remain\r\n" +" unchanged by the FOR loop.\r\n" +" 4. Each command is executed once for each item in the set, with any\r\n" +" occurrence of %indexvar in the command replacing with the current item.\r\n" +" In the second format of FOR ... ENDFOR statement, %indexvar will be\r\n" +" assigned a value from start to end with an interval of step. Start and\r\n" +" end can be any integer whose length is less than 7 digits excluding sign,\r\n" +" and it can also applied to step with one exception of zero. Step is\r\n" +" optional, if step is not specified it will be automatically determined by\r\n" +" following rule:\r\n" +" if start <= end then step = 1, otherwise step = -1.\r\n" +" start, end and step are divided by space.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * Sample FOR loop - listing all .txt files:\r\n" +" echo -off\r\n" +" for %a in *.txt\r\n" +" echo %a exists\r\n" +" endfor\r\n" +" \r\n" +" # \r\n" +" # If in current directory, there are 2 files named file1.txt and file2.txt\r\n" +" # then the output of the sample script will be as shown below.\r\n" +" # \r\n" +" Sample1> echo -off\r\n" +" file1.txt exists\r\n" +" file2.txt exists\r\n" +" \r\n" +" * Theoretically it is legal for 2 nested FOR commands to use the same\r\n" +" alphabet letter as their index variable, for instance, a: \r\n" +" #\r\n" +" # Sample FOR loop from 1 to 3 with step 1\r\n" +" #\r\n" +" echo -off\r\n" +" for %a run (1 3)\r\n" +" echo %a\r\n" +" endfor\r\n" +" \r\n" +" #\r\n" +" # Sample FOR loop from 3 down to 1 with step -1\r\n" +" #\r\n" +" echo -off\r\n" +" for %a run (3 1 -1)\r\n" +" echo %a\r\n" +" endfor\r\n" +" \r\n" +" #\r\n" +" # Sample FOR loop - 2 nested for using same index variable\r\n" +" #\r\n" +" echo -off\r\n" +" for %a in value1 value2\r\n" +" for %a in value3 value4\r\n" +" echo %a\r\n" +" endfor\r\n" +" endfor\r\n" +" \r\n" +" Note: When processing first FOR and before seeing the ENDFOR, the index\r\n" +" variable %a has the value "value1", so in second FOR, the %a has\r\n" +" been already defined and it will be replaced with the current value\r\n" +" of %a. The string after substitution becomes FOR value1 in value3\r\n" +" value4, which is not a legal FOR command. Thus only when the value\r\n" +" of %a is also a single alphabet letter, the script will be executed\r\n" +" without error. If 2 independent FOR commands use the same index\r\n" +" variable, when the second FOR is encountered, the first FOR has\r\n" +" already freed the variable so there will be no problem in this case.\r\n" + +#string STR_GET_HELP_ENDFOR #language en-US "" +".TH endfor 0 "ends a for loop"\r\n" +".SH NAME\r\n" +"Ends a 'for' loop.\r\n" +".SH SYNOPSIS\r\n" +"See 'for' for usage.\r\n" +".SH EXAMPLES\r\n" +"See 'for' for examples.\r\n" + +#string STR_GET_HELP_GOTO #language en-US "" +".TH goto 0 "moves to a label"\r\n" +".SH NAME\r\n" +"Moves around the point of execution in a script.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"GOTO label\r\n" +".SH OPTIONS\r\n" +" \r\n" +" label - Specifies a location in batch file\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. The GOTO command directs script file execution to the line in the script\r\n" +" file after the given label. The command is not supported from the\r\n" +" interactive shell.\r\n" +" 2. A label is a line beginning with a colon (:). It can appear either after\r\n" +" the GOTO command, or before the GOTO command. The search for label is\r\n" +" done forward in the script file, from the current file position. If the\r\n" +" end of the file is reached, the search resumes at the top of the file and\r\n" +" continues until label is found or the starting point is reached. If label\r\n" +" is not found, the script process terminates and an error message is\r\n" +" displayed. If a label is encountered but there is no GOTO command\r\n" +" executed, the label lines are ignored.\r\n" +" 3. Using GOTO command to jump into another for loop is not allowed,\r\n" +" but jumping into an if statement is legal.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * This is a script:\r\n" +" goto Done\r\n" +" ...\r\n" +" :Done\r\n" +" cleanup.nsh\r\n" + +#string STR_GET_HELP_ENDIF #language en-US "" +".TH endif 0 "ends an if block"\r\n" +".SH NAME\r\n" +"Ends the block of a script controlled by an 'if' statement.\r\n" +".SH SYNOPSIS\r\n" +"See 'if' for usage.\r\n" +".SH EXAMPLES\r\n" +"See 'if' for examples.\r\n" + +#string STR_GET_HELP_IF #language en-US "" +".TH if 0 "controls the execution of a block of a script"\r\n" +".SH NAME\r\n" +"Executes commands in specified conditions.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"IF [NOT] EXIST filename THEN\r\n" +" command [arguments]\r\n" +" [command [arguments]]\r\n" +" ...\r\n" +"[ELSE\r\n" +" command [arguments]\r\n" +" [command [arguments]]\r\n" +" ...\r\n" +" ]\r\n" +"ENDIF\r\n" +" \r\n" +"IF [/i] [NOT] string1 == string2 THEN\r\n" +" command [arguments]\r\n" +" [command [arguments]]\r\n" +" ...\r\n" +"[ELSE\r\n" +" command [arguments]\r\n" +" [command [arguments]]\r\n" +" ...\r\n" +" ]\r\n" +"ENDIF\r\n" +"if [/i][/s] ConditionalExpression THEN\r\n" +" command [arguments]\r\n" +" [command [arguments]]\r\n" +" ...\r\n" +"[ELSE\r\n" +" command [arguments]\r\n" +" [command [arguments]]\r\n" +" ...\r\n" +" ]\r\n" +"ENDIF\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. The IF command executes one or more commands before the ELSE or ENDIF\r\n" +" commands, if the specified condition is TRUE; otherwise commands between\r\n" +" ELSE (if present) and ENDIF are executed.\r\n" +" 2. In the first usage of IF, the EXIST condition is true when the file\r\n" +" specified by filename exists. The filename argument may include device\r\n" +" and path information. Also wildcard expansion is supported by this form.\r\n" +" If more than one file matches the wildcard pattern, the condition\r\n" +" evaluates to TRUE.\r\n" +" 3. In the second usage, the string1 == string2 condition is TRUE if the two\r\n" +" strings are identical. Here the comparison can be case sensitive or\r\n" +" insensitive, it depends on the optional switch /i. If /i is specified,\r\n" +" it will compare strings in the case insensitive manner; otherwise, it\r\n" +" compares strings in the case sensitive manner.\r\n" +" 4. In the third usage, general purpose comparison is supported using\r\n" +" expressions optionally separated by AND or OR. Since < and > are used for\r\n" +" redirection, the expressions use common two character (FORTRAN)\r\n" +" abbreviations for the operators (augmented with unsigned equivalents):\r\n" +" - Expressions : Conditional expressions are evaluated strictly from left\r\n" +" to right. Complex conditionals requiring precedence may\r\n" +" be implemented as nested IFs.\r\n" +" The expressions used in the third usage can have the\r\n" +" following syntax:\r\n" +" conditional-expression := expression |\r\n" +" expression and expression |\r\n" +" expression or expression\r\n" +" expression := expr | not expr\r\n" +" expr := item binop item | boolfunc(string)\r\n" +" item := mapfunc(string) | string\r\n" +" mapfunc := efierror | pierror | oemerror\r\n" +" boolfunc := isint | exists | available | profile\r\n" +" binop := gt | lt | eq | ne | ge | le | == | ugt | ult |\r\n" +" uge | ule\r\n" +" - Comparisons : By default, comparisons are done numerically if the\r\n" +" strings on both sides of the operator are numbers\r\n" +" (as defined below) and in case sensitive character sort\r\n" +" order otherwise. Spaces separate the operators from\r\n" +" operands.\r\n" +" 5. The /s option forces string comparisons and the /i option forces\r\n" +" case-insensitive string comparisons. If either of these is used, the\r\n" +" signed or unsigned versions of the operators have the same results.\r\n" +" The /s and /i apply to the entire line and must appear at the start of\r\n" +" the line (just after the if itself). The two may appear in either order.\r\n" +" 6. When performing comparisons, the Unicode Byte Ordering Character is\r\n" +" ignored at the beginning of any argument.\r\n" +" 7. Comparison Operator Definition:\r\n" +" gt : Greater than\r\n" +" ugt : Unsigned Greater than\r\n" +" lt : Less than\r\n" +" ult : Unsigned Less than\r\n" +" ge : Greater than or equal\r\n" +" uge : Unsigned greater than or equal\r\n" +" le : Less than or equal\r\n" +" ule : Unsigned less than or equal\r\n" +" ne : Not equal\r\n" +" eq : Equals (semantically equivalent to ==)\r\n" +" == : Equals (semantically equivalent to eq)\r\n" +" 8. Error Mapping Functions are used to convert integers into UEFI, PI or OEM\r\n" +" error codes.\r\n" +" Functions used to convert integers into UEFI, PI or OEM error codes:\r\n" +" UefiError : Sets top nibble of parameter to 1000 binary (0x8)\r\n" +" PiError : Sets top nibble of parameter to 1010 binary (0xA)\r\n" +" OemError : Sets top nibble of parameter to 1100 binary (0xC)\r\n" +" Each function maps the small positive parameter into its equivalent error\r\n" +" classification.\r\n" +" For example:\r\n" +" if %lasterror% == EfiError(8) then # Check for write protect.\r\n" +" ...\r\n" +" 9. Boolean Functions may only be used to modify operators in comparisons.\r\n" +" The following built-in Boolean functions are also available:\r\n" +" IsInt : Evaluates to true if the parameter string that follows\r\n" +" is a number (as defined below) and false otherwise.\r\n" +" Exists : Evaluates to true if the file specified by string exists\r\n" +" is in the current working directory or false if not.\r\n" +" Available : Evaluates to true if the file specified by string is in the\r\n" +" current working directory or current path.\r\n" +" Profile : Determines whether the parameter string matches one of the\r\n" +" profile names in the profiles environment variable.\r\n" +" 10. No spaces are allowed between function names and the open parenthesis,\r\n" +" between the open parenthesis and the string or between the string and\r\n" +" the closed parenthesis. Constant strings containing spaces must be\r\n" +" quoted.\r\n" +" 11. To avoid ambiguity and current or future incompatibility, users are\r\n" +" strongly encouraged to surround constant strings that contain\r\n" +" parenthesis with quotes in if statements.\r\n" +" 12. Allowable number formats are decimal numbers and C-style case\r\n" +" insensitive hexadecimal numbers. Numbers may be preceded by a\r\n" +" "-" indicating a negative number.\r\n" +" Examples:\r\n" +" 13\r\n" +" 46\r\n" +" -0x3FFF\r\n" +" 0x3fff\r\n" +" 0x1234\r\n" +" 13. Unsigned values must be less than 264. Signed integer values are bounded\r\n" +" by -/+263.\r\n" +" 14. Numbers are internally represented in two's compliment form. The\r\n" +" representation of the number in the string has no bearing on the way\r\n" +" that number is treated in an numeric expression - type is assigned by\r\n" +" the operator. So, for example, -1 lt 2 is true but -1 ult 2 is false.\r\n" +" 15. The IF command is only available in scripts.\r\n" +" 16. The ELSE command is optional in an IF/ELSE statement.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * Sample script for "if" command usages 1 and 2:\r\n" +" if exist fs0:\myscript.nsh then\r\n" +" myscript myarg1 myarg2\r\n" +" endif\r\n" +" if %myvar% == runboth then\r\n" +" myscript1\r\n" +" myscript2\r\n" +" else\r\n" +" echo ^%myvar^% != runboth\r\n" +" endif\r\n" +" Note: In this example, if the script file myscript.nsh exists in fs0:\,\r\n" +" this script will be launched with 2 arguments, myarg1 and myarg2.\r\n" +" After that, environment variable %myvar% is checked to see if its\r\n" +" value is runboth, if so, script myscript1 and myscript2 will be\r\n" +" executed one after the other, otherwise a message %myvar% != runboth\r\n" +" is printed.\r\n" +" \r\n" +" * Sample script for "if" command usage 3:\r\n" +" :Redo\r\n" +" echo Enter 0-6 or q to quit\r\n" +" # assumes "input y" stores a character of user input into variable y\r\n" +" InputCh MyVar\r\n" +" if x%MyVar% eq x then\r\n" +" echo Empty line. Try again\r\n" +" goto Redo\r\n" +" endif\r\n" +" if IsInt(%MyVar%) and %MyVar% le 6 then\r\n" +" myscript1 %MyVar%\r\n" +" goto Redo\r\n" +" endif\r\n" +" if /i %MyVar% ne q then\r\n" +" echo Invalid input\r\n" +" goto Redo\r\n" +" endif\r\n" +" Note: In this example, the script requests user input and uses the if\r\n" +" command for input validation. It checks for empty line first and\r\n" +" then range checks the input.\r\n" + +#string STR_GET_HELP_SHIFT #language en-US "" +".TH shift 0 "move parameters 1 down"\r\n" +".SH NAME\r\n" +"Shifts in-script parameter positions.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"SHIFT\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. The SHIFT command shifts the contents of a UEFI Shell script's positional\r\n" +" parameters so that %1 is discarded, %2 is copied to %1, %3 is copied to\r\n" +" %2, %4 is copied to %3 and so on. This allows UEFI Shell scripts to\r\n" +" process script parameters from left to right.\r\n" +" 2. This command does not change the UEFI shell environment variable\r\n" +" lasterror.\r\n" +" 3. The SHIFT command is available only in UEFI Shell scripts.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * Following script is a sample of 'shift' command:\r\n" +" fs0:\> type shift.nsh\r\n" +" #\r\n" +" # shift.nsh\r\n" +" # \r\n" +" echo %1 %2 %3\r\n" +" shift\r\n" +" echo %1 %2\r\n" +" \r\n" +" * To execute the script with echo on:\r\n" +" fs0:\> shift.nsh welcome UEFI world\r\n" +" shift.nsh> echo welcome UEFI world\r\n" +" welcome UEFI world\r\n" +" shift\r\n" +" echo UEFI world\r\n" +" UEFI world\r\n" +" \r\n" +" * To execute the script with echo off:\r\n" +" fs0:\> echo -off\r\n" +" fs0:\> shift.nsh welcome UEFI world\r\n" +" welcome UEFI world\r\n" +" UEFI world\r\n" + +#string STR_GET_HELP_ELSE #language en-US "" +".TH else 0 "part of an 'if' conditional statement"\r\n" +".SH NAME\r\n" +"Identifies the code executed when 'if' is FALSE.\r\n" +".SH SYNOPSIS\r\n" +"See 'else' for usage.\r\n" +".SH EXAMPLES\r\n" +"See 'if' for examples.\r\n" + +#string STR_GET_HELP_STALL #language en-US "" +".TH stall 0 "stall the operation"\r\n" +".SH NAME\r\n" +"Stalls the operation for a specified number of microseconds.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"STALL time\r\n" +".SH OPTIONS\r\n" +" \r\n" +" time - The number of microseconds for the processor to stall.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command would be used to establish a timed STALL of operations\r\n" +" during a script.\r\n" +" 2. Microseconds is in decimal units.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To stall the processor for 1000000 microseconds:\r\n" +" Shell> stall 1000000\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_NOT_FOUND The requested option was not found.\r\n" +" SHELL_INVALID_PARAMETER One of the passed in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" +" SHELL_DEVICE_ERROR There was a hardware error associated with this\r\n" +" request.\r\n" + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Attrib.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Attrib.c new file mode 100644 index 00000000..5b3d8321 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Attrib.c @@ -0,0 +1,271 @@ +/** @file + Main file for attrib shell level 2 function. + + (C) Copyright 2014-2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel2CommandsLib.h" + +STATIC CONST CHAR16 AllFiles[] = L"*"; + +STATIC CONST SHELL_PARAM_ITEM AttribParamList[] = { + {L"-a", TypeFlag}, + {L"+a", TypeFlag}, + {L"-s", TypeFlag}, + {L"+s", TypeFlag}, + {L"-h", TypeFlag}, + {L"+h", TypeFlag}, + {L"-r", TypeFlag}, + {L"+r", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'attrib' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunAttrib ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + UINT64 FileAttributesToAdd; + UINT64 FileAttributesToRemove; + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + UINTN ParamNumberCount; + CONST CHAR16 *FileName; + EFI_SHELL_FILE_INFO *ListOfFiles; + EFI_SHELL_FILE_INFO *FileNode; + EFI_FILE_INFO *FileInfo; + + ListOfFiles = NULL; + ShellStatus = SHELL_SUCCESS; + ProblemParam = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (AttribParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"attrib", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } else { + FileAttributesToAdd = 0; + FileAttributesToRemove = 0; + + // + // apply or remove each flag + // + if (ShellCommandLineGetFlag(Package, L"+a")) { + FileAttributesToAdd |= EFI_FILE_ARCHIVE; + } + if (ShellCommandLineGetFlag(Package, L"-a")) { + FileAttributesToRemove |= EFI_FILE_ARCHIVE; + } + if (ShellCommandLineGetFlag(Package, L"+s")) { + FileAttributesToAdd |= EFI_FILE_SYSTEM; + } + if (ShellCommandLineGetFlag(Package, L"-s")) { + FileAttributesToRemove |= EFI_FILE_SYSTEM; + } + if (ShellCommandLineGetFlag(Package, L"+h")) { + FileAttributesToAdd |= EFI_FILE_HIDDEN; + } + if (ShellCommandLineGetFlag(Package, L"-h")) { + FileAttributesToRemove |= EFI_FILE_HIDDEN; + } + if (ShellCommandLineGetFlag(Package, L"+r")) { + FileAttributesToAdd |= EFI_FILE_READ_ONLY; + } + if (ShellCommandLineGetFlag(Package, L"-r")) { + FileAttributesToRemove |= EFI_FILE_READ_ONLY; + } + + if (FileAttributesToRemove == 0 && FileAttributesToAdd == 0) { + // + // Do display as we have no attributes to change + // + for ( ParamNumberCount = 1 + ; + ; ParamNumberCount++ + ){ + FileName = ShellCommandLineGetRawValue(Package, ParamNumberCount); + // if we dont have anything left, move on... + if (FileName == NULL && ParamNumberCount == 1) { + FileName = (CHAR16*)AllFiles; + } else if (FileName == NULL) { + break; + } + ASSERT(ListOfFiles == NULL); + Status = ShellOpenFileMetaArg((CHAR16*)FileName, EFI_FILE_MODE_READ, &ListOfFiles); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellLevel2HiiHandle, L"attrib", ShellCommandLineGetRawValue(Package, ParamNumberCount)); + ShellStatus = SHELL_NOT_FOUND; + } else { + for (FileNode = (EFI_SHELL_FILE_INFO*)GetFirstNode(&ListOfFiles->Link) + ; !IsNull(&ListOfFiles->Link, &FileNode->Link) + ; FileNode = (EFI_SHELL_FILE_INFO*)GetNextNode(&ListOfFiles->Link, &FileNode->Link) + ){ + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_ATTRIB_OUTPUT_LINE), + gShellLevel2HiiHandle, + FileNode->Info->Attribute&EFI_FILE_DIRECTORY? L'D':L' ', + FileNode->Info->Attribute&EFI_FILE_ARCHIVE? L'A':L' ', + FileNode->Info->Attribute&EFI_FILE_SYSTEM? L'S':L' ', + FileNode->Info->Attribute&EFI_FILE_HIDDEN? L'H':L' ', + FileNode->Info->Attribute&EFI_FILE_READ_ONLY? L'R':L' ', + FileNode->FileName + ); + + if (ShellGetExecutionBreakFlag()) { + ShellStatus = SHELL_ABORTED; + break; + } + } + Status = ShellCloseFileMetaArg(&ListOfFiles); + ListOfFiles = NULL; + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_CLOSE_FAIL), gShellLevel2HiiHandle, L"attrib", ShellCommandLineGetRawValue(Package, ParamNumberCount)); + ShellStatus = SHELL_NOT_FOUND; + } + } // for loop for handling wildcard filenames + } // for loop for printing out the info + } else if ((FileAttributesToRemove & FileAttributesToAdd) != 0) { + // + // fail as we have conflcting params. + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CON), gShellLevel2HiiHandle, L"attrib"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // enumerate through all the files/directories and apply the attributes + // + for ( ParamNumberCount = 1 + ; + ; ParamNumberCount++ + ){ + FileName = ShellCommandLineGetRawValue(Package, ParamNumberCount); + // if we dont have anything left, move on... + if (FileName == NULL) { + // + // make sure we are not failing on the first one we do... if yes that's an error... + // + if (ParamNumberCount == 1) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"attrib"); + ShellStatus = SHELL_INVALID_PARAMETER; + } + break; + } + + // + // OpenFileByName / GetFileInfo / Change attributes / SetFileInfo / CloseFile / free memory + // for each file or directory on the line. + // + + // + // Open the file(s) + // + ASSERT(ListOfFiles == NULL); + Status = ShellOpenFileMetaArg((CHAR16*)FileName, EFI_FILE_MODE_READ, &ListOfFiles); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellLevel2HiiHandle, L"attrib", ShellCommandLineGetRawValue(Package, ParamNumberCount)); + ShellStatus = SHELL_NOT_FOUND; + } else { + for (FileNode = (EFI_SHELL_FILE_INFO*)GetFirstNode(&ListOfFiles->Link) + ; !IsNull(&ListOfFiles->Link, &FileNode->Link) + ; FileNode = (EFI_SHELL_FILE_INFO*)GetNextNode(&ListOfFiles->Link, &FileNode->Link) + ){ + // + // skip the directory traversing stuff... + // + if (StrCmp(FileNode->FileName, L".") == 0 || StrCmp(FileNode->FileName, L"..") == 0) { + continue; + } + + FileInfo = gEfiShellProtocol->GetFileInfo(FileNode->Handle); + + // + // if we are removing Read-Only we need to do that alone + // + if ((FileAttributesToRemove & EFI_FILE_READ_ONLY) == EFI_FILE_READ_ONLY) { + FileInfo->Attribute &= ~EFI_FILE_READ_ONLY; + // + // SetFileInfo + // + Status = ShellSetFileInfo(FileNode->Handle, FileInfo); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_AD), gShellLevel2HiiHandle, L"attrib", ShellCommandLineGetRawValue(Package, ParamNumberCount)); + ShellStatus = SHELL_ACCESS_DENIED; + } + } + + // + // change the attribute + // + FileInfo->Attribute &= ~FileAttributesToRemove; + FileInfo->Attribute |= FileAttributesToAdd; + + // + // SetFileInfo + // + Status = ShellSetFileInfo(FileNode->Handle, FileInfo); + if (EFI_ERROR(Status)) {; + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_AD), gShellLevel2HiiHandle, L"attrib", ShellCommandLineGetRawValue(Package, ParamNumberCount)); + ShellStatus = SHELL_ACCESS_DENIED; + } + + SHELL_FREE_NON_NULL(FileInfo); + } + Status = ShellCloseFileMetaArg(&ListOfFiles); + ListOfFiles = NULL; + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_CLOSE_FAIL), gShellLevel2HiiHandle, L"attrib", ShellCommandLineGetRawValue(Package, ParamNumberCount)); + ShellStatus = SHELL_NOT_FOUND; + } + } // for loop for handling wildcard filenames + } + } + } + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + + // + // return the status + // + return (ShellStatus); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Cd.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Cd.c new file mode 100644 index 00000000..19bf62cb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Cd.c @@ -0,0 +1,345 @@ +/** @file + Main file for attrib shell level 2 function. + + (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+ (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ Copyright (c) 2018, Dell Technologies. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel2CommandsLib.h" + +/** + Function will replace drive identifier with CWD. + + If FullPath begining with ':' is invalid path, then ASSERT. + If FullPath not include dirve identifier , then do nothing. + If FullPath likes "fs0:\xx" or "fs0:/xx" , then do nothing. + If FullPath likes "fs0:xxx" or "fs0:", the drive replaced by CWD. + + @param[in, out] FullPath The pointer to the string containing the path. + @param[in] Cwd Current directory. + + @retval EFI_SUCCESS Success. + @retval EFI_OUT_OF_SOURCES A memory allocation failed. +**/ +EFI_STATUS +ReplaceDriveWithCwd ( + IN OUT CHAR16 **FullPath, + IN CONST CHAR16 *Cwd + ) +{ + CHAR16 *Splitter; + CHAR16 *TempBuffer; + UINTN TotalSize; + + Splitter = NULL; + TempBuffer = NULL; + TotalSize = 0; + + if (FullPath == NULL || *FullPath == NULL) { + return EFI_SUCCESS; + } + + Splitter = StrStr (*FullPath, L":"); + ASSERT(Splitter != *FullPath); + + if (Splitter != NULL && *(Splitter + 1) != L'\\' && *(Splitter + 1) != L'/') { + TotalSize = StrSize (Cwd) + StrSize (Splitter + 1); + TempBuffer = AllocateZeroPool (TotalSize); + if (TempBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + StrCpyS (TempBuffer, TotalSize / sizeof(CHAR16), Cwd); + StrCatS (TempBuffer, TotalSize / sizeof(CHAR16), L"\\"); + StrCatS (TempBuffer, TotalSize / sizeof(CHAR16), Splitter + 1); + + FreePool(*FullPath); + *FullPath = TempBuffer; + } + + return EFI_SUCCESS; +} + +/** + function to determine if FullPath is under current filesystem. + + @param[in] FullPath The target location to determine. + @param[in] Cwd Current directory. + + @retval TRUE The FullPath is in the current filesystem. + @retval FALSE The FullPaht isn't in the current filesystem. +**/ +BOOLEAN +IsCurrentFileSystem ( + IN CONST CHAR16 *FullPath, + IN CONST CHAR16 *Cwd + ) +{ + CHAR16 *Splitter1; + CHAR16 *Splitter2; + + Splitter1 = NULL; + Splitter2 = NULL; + + ASSERT(FullPath != NULL); + + Splitter1 = StrStr (FullPath, L":"); + if (Splitter1 == NULL) { + return TRUE; + } + + Splitter2 = StrStr (Cwd, L":"); + + if (((UINTN) Splitter1 - (UINTN) FullPath) != ((UINTN) Splitter2 - (UINTN) Cwd)) { + return FALSE; + } else { + if (StrniCmp (FullPath, Cwd, ((UINTN) Splitter1 - (UINTN) FullPath) / sizeof (CHAR16)) == 0) { + return TRUE; + } else { + return FALSE; + } + } +} + +/** + Extract drive string and path string from FullPath. + + The caller must be free Drive and Path. + + @param[in] FullPath A path to be extracted. + @param[out] Drive Buffer to save drive identifier. + @param[out] Path Buffer to save path. + + @retval EFI_SUCCESS Success. + @retval EFI_OUT_OF_RESOUCES A memory allocation failed. +**/ +EFI_STATUS +ExtractDriveAndPath ( + IN CONST CHAR16 *FullPath, + OUT CHAR16 **Drive, + OUT CHAR16 **Path + ) +{ + CHAR16 *Splitter; + + ASSERT (FullPath != NULL); + + Splitter = StrStr (FullPath, L":"); + + if (Splitter == NULL) { + *Drive = NULL; + *Path = AllocateCopyPool (StrSize (FullPath), FullPath); + if (*Path == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } else { + if (*(Splitter + 1) == CHAR_NULL) { + *Drive = AllocateCopyPool (StrSize (FullPath), FullPath); + *Path = NULL; + if (*Drive == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } else { + *Drive = AllocateCopyPool ((Splitter - FullPath + 2) * sizeof(CHAR16), FullPath); + if (*Drive == NULL) { + return EFI_OUT_OF_RESOURCES; + } + (*Drive)[Splitter - FullPath + 1] = CHAR_NULL; + + *Path = AllocateCopyPool (StrSize (Splitter + 1), Splitter + 1); + if (*Path == NULL) { + FreePool (*Drive); + return EFI_OUT_OF_RESOURCES; + } + } + } + + return EFI_SUCCESS; +} + +/** + Function for 'cd' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunCd ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CONST CHAR16 *Cwd; + CHAR16 *Path; + CHAR16 *Drive; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CONST CHAR16 *Param1; + CHAR16 *Param1Copy; + CHAR16 *Walker; + CHAR16 *Splitter; + CHAR16 *TempBuffer; + UINTN TotalSize; + + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + Cwd = NULL; + Path = NULL; + Drive = NULL; + Splitter = NULL; + TempBuffer = NULL; + TotalSize = 0; + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"cd", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } + + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } else if (ShellCommandLineGetRawValue(Package, 2) != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"cd"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // remember that param 0 is the command name + // If there are 0 value parameters, then print the current directory + // else If there are 2 value parameters, then print the error message + // else If there is 1 value paramerer , then change the directory + // + Cwd = ShellGetCurrentDir (NULL); + if (Cwd == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN(STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"cd"); + ShellStatus = SHELL_NOT_FOUND; + } else { + Param1 = ShellCommandLineGetRawValue (Package, 1); + if (Param1 == NULL) { + // + // display the current directory + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN(STR_CD_PRINT), gShellLevel2HiiHandle, Cwd); + } else { + Param1Copy = CatSPrint (NULL, L"%s", Param1, NULL); + for (Walker = Param1Copy; Walker != NULL && *Walker != CHAR_NULL; Walker++) { + if (*Walker == L'\"') { + CopyMem (Walker, Walker + 1, StrSize(Walker) - sizeof(Walker[0])); + } + } + + if (Param1Copy != NULL && IsCurrentFileSystem (Param1Copy, Cwd)) { + Status = ReplaceDriveWithCwd (&Param1Copy,Cwd); + } else { + // + // Can't use cd command to change filesystem. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CD_NF), gShellLevel2HiiHandle, L"cd"); + Status = EFI_NOT_FOUND; + } + + if (!EFI_ERROR(Status) && Param1Copy != NULL) { + Splitter = StrStr (Cwd, L":"); + if (Param1Copy[0] == L'\\') { + // + // Absolute Path on current drive letter. + // + TotalSize = ((Splitter - Cwd + 1) * sizeof(CHAR16)) + StrSize(Param1Copy); + TempBuffer = AllocateZeroPool (TotalSize); + if (TempBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + StrnCpyS (TempBuffer, TotalSize / sizeof(CHAR16), Cwd, (Splitter - Cwd + 1)); + StrCatS (TempBuffer, TotalSize / sizeof(CHAR16), Param1Copy); + + FreePool (Param1Copy); + Param1Copy = TempBuffer; + TempBuffer = NULL; + } + } else { + if (StrStr (Param1Copy,L":") == NULL) { + TotalSize = StrSize (Cwd) + StrSize (Param1Copy); + TempBuffer = AllocateZeroPool (TotalSize); + if (TempBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + StrCpyS (TempBuffer, TotalSize / sizeof (CHAR16), Cwd); + StrCatS (TempBuffer, TotalSize / sizeof (CHAR16), L"\\"); + StrCatS (TempBuffer, TotalSize / sizeof (CHAR16), Param1Copy); + + FreePool (Param1Copy); + Param1Copy = TempBuffer; + TempBuffer = NULL; + } + } + } + } + + if (!EFI_ERROR(Status)) { + Param1Copy = PathCleanUpDirectories (Param1Copy); + Status = ExtractDriveAndPath (Param1Copy, &Drive, &Path); + } + + if (!EFI_ERROR (Status) && Drive != NULL && Path != NULL) { + if (EFI_ERROR(ShellIsDirectory (Param1Copy))) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN(STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cd", Param1Copy); + ShellStatus = SHELL_NOT_FOUND; + } else { + Status = gEfiShellProtocol->SetCurDir (Drive, Path + 1); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN(STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cd", Param1Copy); + ShellStatus = SHELL_NOT_FOUND; + } + } + } + + if (Drive != NULL) { + FreePool (Drive); + } + + if (Path != NULL) { + FreePool (Path); + } + + FreePool (Param1Copy); + } + } + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + + // + // return the status + // + return (ShellStatus); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c new file mode 100644 index 00000000..13f18dfc --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c @@ -0,0 +1,776 @@ +/** @file + Main file for cp shell level 2 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel2CommandsLib.h" +#include +#include + +/** + Function to take a list of files to copy and a destination location and do + the verification and copying of those files to that location. This function + will report any errors to the user and halt. + + @param[in] FileList A LIST_ENTRY* based list of files to move. + @param[in] DestDir The destination location. + @param[in] SilentMode TRUE to eliminate screen output. + @param[in] RecursiveMode TRUE to copy directories. + @param[in] Resp The response to the overwrite query (if always). + + @retval SHELL_SUCCESS the files were all moved. + @retval SHELL_INVALID_PARAMETER a parameter was invalid + @retval SHELL_SECURITY_VIOLATION a security violation ocurred + @retval SHELL_WRITE_PROTECTED the destination was write protected + @retval SHELL_OUT_OF_RESOURCES a memory allocation failed +**/ +SHELL_STATUS +ValidateAndCopyFiles( + IN CONST EFI_SHELL_FILE_INFO *FileList, + IN CONST CHAR16 *DestDir, + IN BOOLEAN SilentMode, + IN BOOLEAN RecursiveMode, + IN VOID **Resp + ); + +/** + Function to Copy one file to another location + + If the destination exists the user will be prompted and the result put into *resp + + @param[in] Source pointer to source file name + @param[in] Dest pointer to destination file name + @param[out] Resp pointer to response from question. Pass back on looped calling + @param[in] SilentMode whether to run in quiet mode or not + @param[in] CmdName Source command name requesting single file copy + + @retval SHELL_SUCCESS The source file was copied to the destination +**/ +SHELL_STATUS +CopySingleFile( + IN CONST CHAR16 *Source, + IN CONST CHAR16 *Dest, + OUT VOID **Resp, + IN BOOLEAN SilentMode, + IN CONST CHAR16 *CmdName + ) +{ + VOID *Response; + UINTN ReadSize; + SHELL_FILE_HANDLE SourceHandle; + SHELL_FILE_HANDLE DestHandle; + EFI_STATUS Status; + VOID *Buffer; + CHAR16 *TempName; + UINTN Size; + EFI_SHELL_FILE_INFO *List; + SHELL_STATUS ShellStatus; + UINT64 SourceFileSize; + UINT64 DestFileSize; + EFI_FILE_PROTOCOL *DestVolumeFP; + EFI_FILE_SYSTEM_INFO *DestVolumeInfo; + UINTN DestVolumeInfoSize; + + ASSERT(Resp != NULL); + + SourceHandle = NULL; + DestHandle = NULL; + Response = *Resp; + List = NULL; + DestVolumeInfo = NULL; + ShellStatus = SHELL_SUCCESS; + + ReadSize = PcdGet32(PcdShellFileOperationSize); + // Why bother copying a file to itself + if (StrCmp(Source, Dest) == 0) { + return (SHELL_SUCCESS); + } + + // + // if the destination file existed check response and possibly prompt user + // + if (ShellFileExists(Dest) == EFI_SUCCESS) { + if (Response == NULL && !SilentMode) { + Status = ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response); + } + // + // possibly return based on response + // + if (!SilentMode) { + if (Response == NULL) { + return SHELL_ABORTED; + } + switch (*(SHELL_PROMPT_RESPONSE*)Response) { + case ShellPromptResponseNo: + // + // return success here so we dont stop the process + // + return (SHELL_SUCCESS); + case ShellPromptResponseCancel: + *Resp = Response; + // + // indicate to stop everything + // + return (SHELL_ABORTED); + case ShellPromptResponseAll: + *Resp = Response; + case ShellPromptResponseYes: + break; + default: + return SHELL_ABORTED; + } + } + } + + if (ShellIsDirectory(Source) == EFI_SUCCESS) { + Status = ShellCreateDirectory(Dest, &DestHandle); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_DIR_FAIL), gShellLevel2HiiHandle, CmdName, Dest); + return (SHELL_ACCESS_DENIED); + } + + // + // Now copy all the files under the directory... + // + TempName = NULL; + Size = 0; + StrnCatGrow(&TempName, &Size, Source, 0); + StrnCatGrow(&TempName, &Size, L"\\*", 0); + if (TempName != NULL) { + ShellOpenFileMetaArg((CHAR16*)TempName, EFI_FILE_MODE_READ, &List); + *TempName = CHAR_NULL; + StrnCatGrow(&TempName, &Size, Dest, 0); + StrnCatGrow(&TempName, &Size, L"\\", 0); + ShellStatus = ValidateAndCopyFiles(List, TempName, SilentMode, TRUE, Resp); + ShellCloseFileMetaArg(&List); + SHELL_FREE_NON_NULL(TempName); + Size = 0; + } + } else { + Status = ShellDeleteFileByName(Dest); + + // + // open file with create enabled + // + Status = ShellOpenFileByName(Dest, &DestHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_OPEN_FAIL), gShellLevel2HiiHandle, CmdName, Dest); + return (SHELL_ACCESS_DENIED); + } + + // + // open source file + // + Status = ShellOpenFileByName (Source, &SourceHandle, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_SRC_OPEN_FAIL), gShellLevel2HiiHandle, CmdName, Source); + return (SHELL_ACCESS_DENIED); + } + + // + //get file size of source file and freespace available on destination volume + // + ShellGetFileSize(SourceHandle, &SourceFileSize); + ShellGetFileSize(DestHandle, &DestFileSize); + + // + //if the destination file already exists then it will be replaced, meaning the sourcefile effectively needs less storage space + // + if(DestFileSize < SourceFileSize){ + SourceFileSize -= DestFileSize; + } else { + SourceFileSize = 0; + } + + // + //get the system volume info to check the free space + // + DestVolumeFP = ConvertShellHandleToEfiFileProtocol(DestHandle); + DestVolumeInfo = NULL; + DestVolumeInfoSize = 0; + Status = DestVolumeFP->GetInfo( + DestVolumeFP, + &gEfiFileSystemInfoGuid, + &DestVolumeInfoSize, + DestVolumeInfo + ); + + if (Status == EFI_BUFFER_TOO_SMALL) { + DestVolumeInfo = AllocateZeroPool(DestVolumeInfoSize); + Status = DestVolumeFP->GetInfo( + DestVolumeFP, + &gEfiFileSystemInfoGuid, + &DestVolumeInfoSize, + DestVolumeInfo + ); + } + + // + //check if enough space available on destination drive to complete copy + // + if (DestVolumeInfo!= NULL && (DestVolumeInfo->FreeSpace < SourceFileSize)) { + // + //not enough space on destination directory to copy file + // + SHELL_FREE_NON_NULL(DestVolumeInfo); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_FAIL), gShellLevel2HiiHandle, CmdName); + return(SHELL_VOLUME_FULL); + } else { + // + // copy data between files + // + Buffer = AllocateZeroPool(ReadSize); + if (Buffer == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellLevel2HiiHandle, CmdName); + return SHELL_OUT_OF_RESOURCES; + } + while (ReadSize == PcdGet32(PcdShellFileOperationSize) && !EFI_ERROR(Status)) { + Status = ShellReadFile(SourceHandle, &ReadSize, Buffer); + if (!EFI_ERROR(Status)) { + Status = ShellWriteFile(DestHandle, &ReadSize, Buffer); + if (EFI_ERROR(Status)) { + ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT)); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_WRITE_ERROR), gShellLevel2HiiHandle, CmdName, Dest); + break; + } + } else { + ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT)); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_READ_ERROR), gShellLevel2HiiHandle, CmdName, Source); + break; + } + } + } + SHELL_FREE_NON_NULL(DestVolumeInfo); + } + + // + // close files + // + if (DestHandle != NULL) { + ShellCloseFile(&DestHandle); + DestHandle = NULL; + } + if (SourceHandle != NULL) { + ShellCloseFile(&SourceHandle); + SourceHandle = NULL; + } + + // + // return + // + return ShellStatus; +} + +/** + function to take a list of files to copy and a destination location and do + the verification and copying of those files to that location. This function + will report any errors to the user and halt. + + The key is to have this function called ONLY once. this allows for the parameter + verification to happen correctly. + + @param[in] FileList A LIST_ENTRY* based list of files to move. + @param[in] DestDir The destination location. + @param[in] SilentMode TRUE to eliminate screen output. + @param[in] RecursiveMode TRUE to copy directories. + @param[in] Resp The response to the overwrite query (if always). + + @retval SHELL_SUCCESS the files were all moved. + @retval SHELL_INVALID_PARAMETER a parameter was invalid + @retval SHELL_SECURITY_VIOLATION a security violation ocurred + @retval SHELL_WRITE_PROTECTED the destination was write protected + @retval SHELL_OUT_OF_RESOURCES a memory allocation failed +**/ +SHELL_STATUS +ValidateAndCopyFiles( + IN CONST EFI_SHELL_FILE_INFO *FileList, + IN CONST CHAR16 *DestDir, + IN BOOLEAN SilentMode, + IN BOOLEAN RecursiveMode, + IN VOID **Resp + ) +{ + CHAR16 *HiiOutput; + CHAR16 *HiiResultOk; + CONST EFI_SHELL_FILE_INFO *Node; + SHELL_STATUS ShellStatus; + EFI_STATUS Status; + CHAR16 *DestPath; + VOID *Response; + UINTN PathSize; + CONST CHAR16 *Cwd; + UINTN NewSize; + CHAR16 *CleanFilePathStr; + + if (Resp == NULL) { + Response = NULL; + } else { + Response = *Resp; + } + + DestPath = NULL; + ShellStatus = SHELL_SUCCESS; + PathSize = 0; + Cwd = ShellGetCurrentDir(NULL); + CleanFilePathStr = NULL; + + ASSERT(FileList != NULL); + ASSERT(DestDir != NULL); + + + Status = ShellLevel2StripQuotes (DestDir, &CleanFilePathStr); + if (EFI_ERROR (Status)) { + if (Status == EFI_OUT_OF_RESOURCES) { + return SHELL_OUT_OF_RESOURCES; + } else { + return SHELL_INVALID_PARAMETER; + } + } + + ASSERT (CleanFilePathStr != NULL); + + // + // If we are trying to copy multiple files... make sure we got a directory for the target... + // + if (EFI_ERROR(ShellIsDirectory(CleanFilePathStr)) && FileList->Link.ForwardLink != FileList->Link.BackLink) { + // + // Error for destination not a directory + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); + FreePool (CleanFilePathStr); + return (SHELL_INVALID_PARAMETER); + } + for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link) + ; !IsNull(&FileList->Link, &Node->Link) + ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link) + ){ + // + // skip the directory traversing stuff... + // + if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) { + continue; + } + + NewSize = StrSize(CleanFilePathStr); + NewSize += StrSize(Node->FullName); + NewSize += (Cwd == NULL)? 0 : (StrSize(Cwd) + sizeof(CHAR16)); + if (NewSize > PathSize) { + PathSize = NewSize; + } + + // + // Make sure got -r if required + // + if (!RecursiveMode && !EFI_ERROR(ShellIsDirectory(Node->FullName))) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_REQ), gShellLevel2HiiHandle, L"cp"); + FreePool (CleanFilePathStr); + return (SHELL_INVALID_PARAMETER); + } + + // + // make sure got dest as dir if needed + // + if (!EFI_ERROR(ShellIsDirectory(Node->FullName)) && EFI_ERROR(ShellIsDirectory(CleanFilePathStr))) { + // + // Error for destination not a directory + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); + FreePool (CleanFilePathStr); + return (SHELL_INVALID_PARAMETER); + } + } + + HiiOutput = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_CP_OUTPUT), NULL); + HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL); + DestPath = AllocateZeroPool(PathSize); + + if (DestPath == NULL || HiiOutput == NULL || HiiResultOk == NULL) { + SHELL_FREE_NON_NULL(DestPath); + SHELL_FREE_NON_NULL(HiiOutput); + SHELL_FREE_NON_NULL(HiiResultOk); + FreePool (CleanFilePathStr); + return (SHELL_OUT_OF_RESOURCES); + } + + // + // Go through the list of files to copy... + // + for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link) + ; !IsNull(&FileList->Link, &Node->Link) + ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link) + ){ + if (ShellGetExecutionBreakFlag()) { + break; + } + ASSERT(Node->FileName != NULL); + ASSERT(Node->FullName != NULL); + + // + // skip the directory traversing stuff... + // + if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) { + continue; + } + + if (FileList->Link.ForwardLink == FileList->Link.BackLink // 1 item + && EFI_ERROR(ShellIsDirectory(CleanFilePathStr)) // not an existing directory + ) { + if (StrStr(CleanFilePathStr, L":") == NULL) { + // + // simple copy of a single file + // + if (Cwd != NULL) { + StrCpyS(DestPath, PathSize / sizeof(CHAR16), Cwd); + StrCatS(DestPath, PathSize / sizeof(CHAR16), L"\\"); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); + FreePool (CleanFilePathStr); + return (SHELL_INVALID_PARAMETER); + } + if (DestPath[StrLen(DestPath)-1] != L'\\' && CleanFilePathStr[0] != L'\\') { + StrCatS(DestPath, PathSize / sizeof(CHAR16), L"\\"); + } else if (DestPath[StrLen(DestPath)-1] == L'\\' && CleanFilePathStr[0] == L'\\') { + ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL; + } + StrCatS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr); + } else { + StrCpyS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr); + } + } else { + // + // we have multiple files or a directory in the DestDir + // + + // + // Check for leading slash + // + if (CleanFilePathStr[0] == L'\\') { + // + // Copy to the root of CWD + // + if (Cwd != NULL) { + StrCpyS(DestPath, PathSize/sizeof(CHAR16), Cwd); + StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\"); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); + FreePool(CleanFilePathStr); + return (SHELL_INVALID_PARAMETER); + } + while (PathRemoveLastItem(DestPath)); + StrCatS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr+1); + StrCatS(DestPath, PathSize/sizeof(CHAR16), Node->FileName); + } else if (StrStr(CleanFilePathStr, L":") == NULL) { + if (Cwd != NULL) { + StrCpyS(DestPath, PathSize/sizeof(CHAR16), Cwd); + StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\"); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); + FreePool(CleanFilePathStr); + return (SHELL_INVALID_PARAMETER); + } + if (DestPath[StrLen(DestPath)-1] != L'\\' && CleanFilePathStr[0] != L'\\') { + StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\"); + } else if (DestPath[StrLen(DestPath)-1] == L'\\' && CleanFilePathStr[0] == L'\\') { + ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL; + } + StrCatS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr); + if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] != L'\\' && Node->FileName[0] != L'\\') { + StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\"); + } else if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] == L'\\' && Node->FileName[0] == L'\\') { + ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL; + } + StrCatS(DestPath, PathSize/sizeof(CHAR16), Node->FileName); + + } else { + StrCpyS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr); + if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] != L'\\' && Node->FileName[0] != L'\\') { + StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\"); + } else if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] == L'\\' && Node->FileName[0] == L'\\') { + ((CHAR16*)CleanFilePathStr)[StrLen(CleanFilePathStr)-1] = CHAR_NULL; + } + StrCatS(DestPath, PathSize/sizeof(CHAR16), Node->FileName); + } + } + + // + // Make sure the path exists + // + if (EFI_ERROR(VerifyIntermediateDirectories(DestPath))) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_WNF), gShellLevel2HiiHandle, L"cp", DestPath); + ShellStatus = SHELL_DEVICE_ERROR; + break; + } + + if ( !EFI_ERROR(ShellIsDirectory(Node->FullName)) + && !EFI_ERROR(ShellIsDirectory(DestPath)) + && StrniCmp(Node->FullName, DestPath, StrLen(DestPath)) == 0 + ){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_PARENT), gShellLevel2HiiHandle, L"cp"); + ShellStatus = SHELL_INVALID_PARAMETER; + break; + } + if (StringNoCaseCompare(&Node->FullName, &DestPath) == 0) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp"); + ShellStatus = SHELL_INVALID_PARAMETER; + break; + } + + if ((StrniCmp(Node->FullName, DestPath, StrLen(Node->FullName)) == 0) + && (DestPath[StrLen(Node->FullName)] == CHAR_NULL || DestPath[StrLen(Node->FullName)] == L'\\') + ) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp"); + ShellStatus = SHELL_INVALID_PARAMETER; + break; + } + + PathCleanUpDirectories(DestPath); + + if (!SilentMode) { + ShellPrintEx(-1, -1, HiiOutput, Node->FullName, DestPath); + } + + // + // copy single file... + // + ShellStatus = CopySingleFile(Node->FullName, DestPath, &Response, SilentMode, L"cp"); + if (ShellStatus != SHELL_SUCCESS) { + break; + } + } + if (ShellStatus == SHELL_SUCCESS && Resp == NULL) { + ShellPrintEx(-1, -1, L"%s", HiiResultOk); + } + + SHELL_FREE_NON_NULL(DestPath); + SHELL_FREE_NON_NULL(HiiOutput); + SHELL_FREE_NON_NULL(HiiResultOk); + SHELL_FREE_NON_NULL(CleanFilePathStr); + if (Resp == NULL) { + SHELL_FREE_NON_NULL(Response); + } + + return (ShellStatus); + +} + +/** + Validate and if successful copy all the files from the list into + destination directory. + + @param[in] FileList The list of files to copy. + @param[in] DestDir The directory to copy files to. + @param[in] SilentMode TRUE to eliminate screen output. + @param[in] RecursiveMode TRUE to copy directories. + + @retval SHELL_INVALID_PARAMETER A parameter was invalid. + @retval SHELL_SUCCESS The operation was successful. +**/ +SHELL_STATUS +ProcessValidateAndCopyFiles( + IN EFI_SHELL_FILE_INFO *FileList, + IN CONST CHAR16 *DestDir, + IN BOOLEAN SilentMode, + IN BOOLEAN RecursiveMode + ) +{ + SHELL_STATUS ShellStatus; + EFI_SHELL_FILE_INFO *List; + EFI_FILE_INFO *FileInfo; + CHAR16 *FullName; + + List = NULL; + FullName = NULL; + FileInfo = NULL; + + ShellOpenFileMetaArg((CHAR16*)DestDir, EFI_FILE_MODE_READ, &List); + if (List != NULL && List->Link.ForwardLink != List->Link.BackLink) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, L"cp", DestDir); + ShellStatus = SHELL_INVALID_PARAMETER; + ShellCloseFileMetaArg(&List); + } else if (List != NULL) { + ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink) != NULL); + ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName != NULL); + FileInfo = gEfiShellProtocol->GetFileInfo(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->Handle); + ASSERT(FileInfo != NULL); + StrnCatGrow(&FullName, NULL, ((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName, 0); + ShellCloseFileMetaArg(&List); + if ((FileInfo->Attribute & EFI_FILE_READ_ONLY) == 0) { + ShellStatus = ValidateAndCopyFiles(FileList, FullName, SilentMode, RecursiveMode, NULL); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_ERROR), gShellLevel2HiiHandle, L"cp"); + ShellStatus = SHELL_ACCESS_DENIED; + } + } else { + ShellCloseFileMetaArg(&List); + ShellStatus = ValidateAndCopyFiles(FileList, DestDir, SilentMode, RecursiveMode, NULL); + } + + SHELL_FREE_NON_NULL(FileInfo); + SHELL_FREE_NON_NULL(FullName); + return (ShellStatus); +} + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-r", TypeFlag}, + {L"-q", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'cp' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunCp ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + UINTN ParamCount; + UINTN LoopCounter; + EFI_SHELL_FILE_INFO *FileList; + BOOLEAN SilentMode; + BOOLEAN RecursiveMode; + CONST CHAR16 *Cwd; + CHAR16 *FullCwd; + + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + ParamCount = 0; + FileList = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"cp", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } + + // + // Initialize SilentMode and RecursiveMode + // + if (gEfiShellProtocol->BatchIsActive()) { + SilentMode = TRUE; + } else { + SilentMode = ShellCommandLineGetFlag(Package, L"-q"); + } + RecursiveMode = ShellCommandLineGetFlag(Package, L"-r"); + + switch (ParamCount = ShellCommandLineGetCount(Package)) { + case 0: + case 1: + // + // we have insufficient parameters + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"cp"); + ShellStatus = SHELL_INVALID_PARAMETER; + break; + case 2: + // + // must have valid CWD for single parameter... + // + Cwd = ShellGetCurrentDir(NULL); + if (Cwd == NULL){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"cp"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList); + if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, 1)); + ShellStatus = SHELL_NOT_FOUND; + } else { + FullCwd = AllocateZeroPool(StrSize(Cwd) + sizeof(CHAR16)); + if (FullCwd == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellLevel2HiiHandle, L"cp"); + ShellStatus = SHELL_OUT_OF_RESOURCES; + } else { + StrCpyS (FullCwd, StrSize (Cwd) / sizeof (CHAR16) + 1, Cwd); + ShellStatus = ProcessValidateAndCopyFiles (FileList, FullCwd, SilentMode, RecursiveMode); + FreePool (FullCwd); + } + } + } + + break; + default: + // + // Make a big list of all the files... + // + for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount && ShellStatus == SHELL_SUCCESS ; LoopCounter++) { + if (ShellGetExecutionBreakFlag()) { + break; + } + Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList); + if (EFI_ERROR(Status) || FileList == NULL || IsListEmpty(&FileList->Link)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, LoopCounter)); + ShellStatus = SHELL_NOT_FOUND; + } + } + if (ShellStatus != SHELL_SUCCESS) { + Status = ShellCloseFileMetaArg(&FileList); + } else { + // + // now copy them all... + // + if (FileList != NULL && !IsListEmpty(&FileList->Link)) { + ShellStatus = ProcessValidateAndCopyFiles(FileList, PathCleanUpDirectories((CHAR16*)ShellCommandLineGetRawValue(Package, ParamCount)), SilentMode, RecursiveMode); + Status = ShellCloseFileMetaArg(&FileList); + if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, ParamCount), ShellStatus|MAX_BIT); + ShellStatus = SHELL_ACCESS_DENIED; + } + } + } + break; + } // switch on parameter count + + if (FileList != NULL) { + ShellCloseFileMetaArg(&FileList); + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + } + + if (ShellGetExecutionBreakFlag()) { + return (SHELL_ABORTED); + } + + return (ShellStatus); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Load.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Load.c new file mode 100644 index 00000000..c2a41038 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Load.c @@ -0,0 +1,282 @@ +/** @file + Main file for attrib shell level 2 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel2CommandsLib.h" + +// This function was from from the BdsLib implementation in +// IntelFrameworkModulePkg\Library\GenericBdsLib\BdsConnect.c +// function name: BdsLibConnectAllEfi +/** + This function will connect all current system handles recursively. The + connection will finish until every handle's child handle created if it have. + + @retval EFI_SUCCESS All handles and it's child handle have been + connected + @retval EFI_STATUS Return the status of gBS->LocateHandleBuffer(). + +**/ +EFI_STATUS +ConnectAllEfi ( + VOID + ) +{ + EFI_STATUS Status; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN Index; + + Status = gBS->LocateHandleBuffer ( + AllHandles, + NULL, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE); + } + + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + + return EFI_SUCCESS; +} + +/** + function to load a .EFI driver into memory and possible connect the driver. + + if FileName is NULL then ASSERT. + + @param[in] FileName FileName of the driver to load + @param[in] Connect Whether to connect or not + + @retval EFI_SUCCESS the driver was loaded and if Connect was + true then connect was attempted. Connection may + have failed. + @retval EFI_OUT_OF_RESOURCES there was insufficient memory +**/ +EFI_STATUS +LoadDriver( + IN CONST CHAR16 *FileName, + IN CONST BOOLEAN Connect + ) +{ + EFI_HANDLE LoadedDriverHandle; + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *FilePath; + EFI_LOADED_IMAGE_PROTOCOL *LoadedDriverImage; + + LoadedDriverImage = NULL; + FilePath = NULL; + LoadedDriverHandle = NULL; + Status = EFI_SUCCESS; + + ASSERT (FileName != NULL); + + // + // Fix local copies of the protocol pointers + // + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // Convert to DEVICE_PATH + // + FilePath = gEfiShellProtocol->GetDevicePathFromFilePath(FileName); + + if (FilePath == NULL) { + ASSERT(FALSE); + return (EFI_INVALID_PARAMETER); + } + + // + // Use LoadImage to get it into memory + // + Status = gBS->LoadImage( + FALSE, + gImageHandle, + FilePath, + NULL, + 0, + &LoadedDriverHandle); + + if (EFI_ERROR(Status)) { + // + // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created + // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now. + // If the caller doesn't have the option to defer the execution of an image, we should + // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak. + // + if (Status == EFI_SECURITY_VIOLATION) { + gBS->UnloadImage (LoadedDriverHandle); + } + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LOAD_NOT_IMAGE), gShellLevel2HiiHandle, FileName, Status); + } else { + // + // Make sure it is a driver image + // + Status = gBS->HandleProtocol (LoadedDriverHandle, &gEfiLoadedImageProtocolGuid, (VOID *) &LoadedDriverImage); + + ASSERT (LoadedDriverImage != NULL); + + if ( EFI_ERROR(Status) + || ( LoadedDriverImage->ImageCodeType != EfiBootServicesCode + && LoadedDriverImage->ImageCodeType != EfiRuntimeServicesCode) + ){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LOAD_NOT_DRIVER), gShellLevel2HiiHandle, FileName); + + // + // Exit and unload the non-driver image + // + gBS->Exit(LoadedDriverHandle, EFI_INVALID_PARAMETER, 0, NULL); + Status = EFI_INVALID_PARAMETER; + } + } + + if (!EFI_ERROR(Status)) { + // + // Start the image + // + Status = gBS->StartImage(LoadedDriverHandle, NULL, NULL); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LOAD_ERROR), gShellLevel2HiiHandle, FileName, Status); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LOAD_LOADED), gShellLevel2HiiHandle, FileName, LoadedDriverImage->ImageBase, Status); + } + } + + if (!EFI_ERROR(Status) && Connect) { + // + // Connect it... + // + Status = ConnectAllEfi(); + } + + // + // clean up memory... + // + if (FilePath != NULL) { + FreePool(FilePath); + } + + return (Status); +} + +STATIC CONST SHELL_PARAM_ITEM LoadParamList[] = { + {L"-nc", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'load' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunLoad ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + UINTN ParamCount; + EFI_SHELL_FILE_INFO *ListHead; + EFI_SHELL_FILE_INFO *Node; + + ListHead = NULL; + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (LoadParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"load", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } else if (ShellCommandLineGetRawValue(Package, 1) == NULL) { + // + // we didnt get a single file to load parameter + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"load"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + for ( ParamCount = 1 + ; ShellCommandLineGetRawValue(Package, ParamCount) != NULL + ; ParamCount++ + ){ + Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, ParamCount), EFI_FILE_MODE_READ, &ListHead); + if (!EFI_ERROR(Status)) { + for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link) + ; !IsNull(&ListHead->Link, &Node->Link) + ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link) + ){ + // + // once we have an error preserve that value, but finish the loop. + // + if (EFI_ERROR(Status)) { + LoadDriver(Node->FullName, (BOOLEAN)(ShellCommandLineGetFlag(Package, L"-nc")==FALSE)); + } else { + Status = LoadDriver(Node->FullName, (BOOLEAN)(ShellCommandLineGetFlag(Package, L"-nc")==FALSE)); + } + } // for loop for multi-open + if (EFI_ERROR(Status)) { + ShellCloseFileMetaArg(&ListHead); + } else { + Status = ShellCloseFileMetaArg(&ListHead);; + } + } else { + // + // no files found. + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"load", (CHAR16*)ShellCommandLineGetRawValue(Package, ParamCount)); + ShellStatus = SHELL_NOT_FOUND; + } + } // for loop for params + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + } + + if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) { + ShellStatus = SHELL_DEVICE_ERROR; + } + + return (ShellStatus); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c new file mode 100644 index 00000000..f28d2728 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c @@ -0,0 +1,905 @@ +/** @file + Main file for ls shell level 2 function. + + (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel2CommandsLib.h" +#include + +UINTN mDayOfMonth[] = {31, 28, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30}; + +/** + print out the standard format output volume entry. + + @param[in] TheList a list of files from the volume. +**/ +EFI_STATUS +PrintSfoVolumeInfoTableEntry( + IN CONST EFI_SHELL_FILE_INFO *TheList + ) +{ + EFI_STATUS Status; + EFI_SHELL_FILE_INFO *Node; + CHAR16 *DirectoryName; + EFI_FILE_SYSTEM_INFO *SysInfo; + UINTN SysInfoSize; + SHELL_FILE_HANDLE ShellFileHandle; + EFI_FILE_PROTOCOL *EfiFpHandle; + + // + // Get the first valid handle (directories) + // + for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&TheList->Link) + ; !IsNull(&TheList->Link, &Node->Link) && Node->Handle == NULL + ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&TheList->Link, &Node->Link) + ); + + if (Node->Handle == NULL) { + DirectoryName = GetFullyQualifiedPath(((EFI_SHELL_FILE_INFO *)GetFirstNode(&TheList->Link))->FullName); + + // + // We need to open something up to get system information + // + Status = gEfiShellProtocol->OpenFileByName( + DirectoryName, + &ShellFileHandle, + EFI_FILE_MODE_READ + ); + + ASSERT_EFI_ERROR(Status); + FreePool(DirectoryName); + + // + // Get the Volume Info from ShellFileHandle + // + SysInfo = NULL; + SysInfoSize = 0; + EfiFpHandle = ConvertShellHandleToEfiFileProtocol(ShellFileHandle); + Status = EfiFpHandle->GetInfo( + EfiFpHandle, + &gEfiFileSystemInfoGuid, + &SysInfoSize, + SysInfo + ); + + if (Status == EFI_BUFFER_TOO_SMALL) { + SysInfo = AllocateZeroPool(SysInfoSize); + Status = EfiFpHandle->GetInfo( + EfiFpHandle, + &gEfiFileSystemInfoGuid, + &SysInfoSize, + SysInfo + ); + } + + ASSERT_EFI_ERROR(Status); + + gEfiShellProtocol->CloseFile(ShellFileHandle); + } else { + // + // Get the Volume Info from Node->Handle + // + SysInfo = NULL; + SysInfoSize = 0; + EfiFpHandle = ConvertShellHandleToEfiFileProtocol(Node->Handle); + Status = EfiFpHandle->GetInfo( + EfiFpHandle, + &gEfiFileSystemInfoGuid, + &SysInfoSize, + SysInfo + ); + + if (Status == EFI_BUFFER_TOO_SMALL) { + SysInfo = AllocateZeroPool(SysInfoSize); + Status = EfiFpHandle->GetInfo( + EfiFpHandle, + &gEfiFileSystemInfoGuid, + &SysInfoSize, + SysInfo + ); + } + + ASSERT_EFI_ERROR(Status); + } + + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_GEN_SFO_HEADER), + gShellLevel2HiiHandle, + L"ls" + ); + // + // print VolumeInfo table + // + ASSERT(SysInfo != NULL); + ShellPrintHiiEx ( + 0, + gST->ConOut->Mode->CursorRow, + NULL, + STRING_TOKEN (STR_LS_SFO_VOLINFO), + gShellLevel2HiiHandle, + SysInfo->VolumeLabel, + SysInfo->VolumeSize, + SysInfo->ReadOnly?L"TRUE":L"FALSE", + SysInfo->FreeSpace, + SysInfo->BlockSize + ); + + SHELL_FREE_NON_NULL(SysInfo); + + return (Status); +} + +/** + print out the info on a single file. + + @param[in] Sfo TRUE if in SFO, false otherwise. + @param[in] TheNode the EFI_SHELL_FILE_INFO node to print out information on. + @param[in] Files incremented if a file is printed. + @param[in] Size incremented by file size. + @param[in] Dirs incremented if a directory is printed. + +**/ +VOID +PrintFileInformation( + IN CONST BOOLEAN Sfo, + IN CONST EFI_SHELL_FILE_INFO *TheNode, + IN UINT64 *Files, + IN UINT64 *Size, + IN UINT64 *Dirs + ) +{ + ASSERT(Files != NULL); + ASSERT(Size != NULL); + ASSERT(Dirs != NULL); + ASSERT(TheNode != NULL); + + if (Sfo) { + // + // Print the FileInfo Table + // + ShellPrintHiiEx ( + 0, + gST->ConOut->Mode->CursorRow, + NULL, + STRING_TOKEN (STR_LS_SFO_FILEINFO), + gShellLevel2HiiHandle, + TheNode->FullName, + TheNode->Info->FileSize, + TheNode->Info->PhysicalSize, + (TheNode->Info->Attribute & EFI_FILE_ARCHIVE) != 0?L"a":L"", + (TheNode->Info->Attribute & EFI_FILE_DIRECTORY) != 0?L"d":L"", + (TheNode->Info->Attribute & EFI_FILE_HIDDEN) != 0?L"h":L"", + (TheNode->Info->Attribute & EFI_FILE_READ_ONLY) != 0?L"r":L"", + (TheNode->Info->Attribute & EFI_FILE_SYSTEM) != 0?L"s":L"", + TheNode->Info->CreateTime.Hour, + TheNode->Info->CreateTime.Minute, + TheNode->Info->CreateTime.Second, + TheNode->Info->CreateTime.Day, + TheNode->Info->CreateTime.Month, + TheNode->Info->CreateTime.Year, + TheNode->Info->LastAccessTime.Hour, + TheNode->Info->LastAccessTime.Minute, + TheNode->Info->LastAccessTime.Second, + TheNode->Info->LastAccessTime.Day, + TheNode->Info->LastAccessTime.Month, + TheNode->Info->LastAccessTime.Year, + TheNode->Info->ModificationTime.Hour, + TheNode->Info->ModificationTime.Minute, + TheNode->Info->ModificationTime.Second, + TheNode->Info->ModificationTime.Day, + TheNode->Info->ModificationTime.Month, + TheNode->Info->ModificationTime.Year + ); + } else { + // + // print this one out... + // first print the universal start, next print the type specific name format, last print the CRLF + // + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_LS_LINE_START_ALL), + gShellLevel2HiiHandle, + &TheNode->Info->ModificationTime, + (TheNode->Info->Attribute & EFI_FILE_DIRECTORY) != 0?L"":L"", + (TheNode->Info->Attribute & EFI_FILE_READ_ONLY) != 0?L'r':L' ', + TheNode->Info->FileSize + ); + if (TheNode->Info->Attribute & EFI_FILE_DIRECTORY) { + (*Dirs)++; + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_LS_LINE_END_DIR), + gShellLevel2HiiHandle, + TheNode->FileName + ); + } else { + (*Files)++; + (*Size) += TheNode->Info->FileSize; + if ( (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)L".nsh", (CHAR16*)&(TheNode->FileName[StrLen (TheNode->FileName) - 4])) == 0) + || (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)L".efi", (CHAR16*)&(TheNode->FileName[StrLen (TheNode->FileName) - 4])) == 0) + ){ + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_LS_LINE_END_EXE), + gShellLevel2HiiHandle, + TheNode->FileName + ); + } else { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_LS_LINE_END_FILE), + gShellLevel2HiiHandle, + TheNode->FileName + ); + } + } + } +} + +/** + print out the header when not using standard format output. + + @param[in] Path String with starting path. +**/ +VOID +PrintNonSfoHeader( + IN CONST CHAR16 *Path + ) +{ + CHAR16 *DirectoryName; + + // + // get directory name from path... + // + DirectoryName = GetFullyQualifiedPath(Path); + + if (DirectoryName != NULL) { + // + // print header + // + ShellPrintHiiEx ( + 0, + gST->ConOut->Mode->CursorRow, + NULL, + STRING_TOKEN (STR_LS_HEADER_LINE1), + gShellLevel2HiiHandle, + DirectoryName + ); + + SHELL_FREE_NON_NULL(DirectoryName); + } +} + +/** + print out the footer when not using standard format output. + + @param[in] Files The number of files. + @param[in] Size The size of files in bytes. + @param[in] Dirs The number of directories. +**/ +VOID +PrintNonSfoFooter( + IN UINT64 Files, + IN UINT64 Size, + IN UINT64 Dirs + ) +{ + // + // print footer + // + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_LS_FOOTER_LINE), + gShellLevel2HiiHandle, + Files, + Size, + Dirs + ); +} + +/** + Change the file time to local time based on the timezone. + + @param[in] Time The file time. + @param[in] LocalTimeZone Local time zone. +**/ +VOID +FileTimeToLocalTime ( + IN EFI_TIME *Time, + IN INT16 LocalTimeZone + ) +{ + INTN MinuteDiff; + INTN TempMinute; + INTN HourNumberOfTempMinute; + INTN TempHour; + INTN DayNumberOfTempHour; + INTN TempDay; + INTN MonthNumberOfTempDay; + INTN TempMonth; + INTN YearNumberOfTempMonth; + INTN MonthRecord; + + ASSERT ((Time->TimeZone >= -1440) && (Time->TimeZone <=1440)); + ASSERT ((LocalTimeZone >= -1440) && (LocalTimeZone <=1440)); + ASSERT ((Time->Month >= 1) && (Time->Month <= 12)); + + if(Time->TimeZone == LocalTimeZone) { + // + //if the file timezone is equal to the local timezone, there is no need to adjust the file time. + // + return; + } + + if((Time->Year % 4 == 0 && Time->Year / 100 != 0)||(Time->Year % 400 == 0)) { + // + // Day in February of leap year is 29. + // + mDayOfMonth[1] = 29; + } + + MinuteDiff = Time->TimeZone - LocalTimeZone; + TempMinute = Time->Minute + MinuteDiff; + + // + // Calculate Time->Minute + // TempHour will be used to calculate Time->Hour + // + HourNumberOfTempMinute = TempMinute / 60; + if(TempMinute < 0) { + HourNumberOfTempMinute --; + } + TempHour = Time->Hour + HourNumberOfTempMinute; + Time->Minute = (UINT8)(TempMinute - 60 * HourNumberOfTempMinute); + + // + // Calculate Time->Hour + // TempDay will be used to calculate Time->Day + // + DayNumberOfTempHour = TempHour / 24 ; + if(TempHour < 0){ + DayNumberOfTempHour--; + } + TempDay = Time->Day + DayNumberOfTempHour; + Time->Hour = (UINT8)(TempHour - 24 * DayNumberOfTempHour); + + // + // Calculate Time->Day + // TempMonth will be used to calculate Time->Month + // + MonthNumberOfTempDay = (TempDay - 1) / (INTN)mDayOfMonth[Time->Month - 1]; + MonthRecord = (INTN)(Time->Month) ; + if(TempDay - 1 < 0){ + MonthNumberOfTempDay -- ; + MonthRecord -- ; + } + TempMonth = Time->Month + MonthNumberOfTempDay; + Time->Day = (UINT8)(TempDay - (INTN)mDayOfMonth[(MonthRecord - 1 + 12) % 12] * MonthNumberOfTempDay); + + // + // Calculate Time->Month, Time->Year + // + YearNumberOfTempMonth = (TempMonth - 1) / 12; + if(TempMonth - 1 < 0){ + YearNumberOfTempMonth --; + } + Time->Month = (UINT8)(TempMonth - 12 * (YearNumberOfTempMonth)); + Time->Year = (UINT16)(Time->Year + YearNumberOfTempMonth); +} + +/** + print out the list of files and directories from the LS command + + @param[in] Rec TRUE to automatically recurse into each found directory + FALSE to only list the specified directory. + @param[in] Attribs List of required Attribute for display. + If 0 then all non-system and non-hidden files will be printed. + @param[in] Sfo TRUE to use Standard Format Output, FALSE otherwise + @param[in] RootPath String with starting path to search in. + @param[in] SearchString String with search string. + @param[in] Found Set to TRUE, if anyone were found. + @param[in] Count The count of bits enabled in Attribs. + @param[in] TimeZone The current time zone offset. + @param[in] ListUnfiltered TRUE to request listing the directory contents + unfiltered. + + @retval SHELL_SUCCESS the printing was sucessful. +**/ +SHELL_STATUS +PrintLsOutput( + IN CONST BOOLEAN Rec, + IN CONST UINT64 Attribs, + IN CONST BOOLEAN Sfo, + IN CONST CHAR16 *RootPath, + IN CONST CHAR16 *SearchString, + IN BOOLEAN *Found, + IN CONST UINTN Count, + IN CONST INT16 TimeZone, + IN CONST BOOLEAN ListUnfiltered + ) +{ + EFI_STATUS Status; + EFI_SHELL_FILE_INFO *ListHead; + EFI_SHELL_FILE_INFO *Node; + SHELL_STATUS ShellStatus; + UINT64 FileCount; + UINT64 DirCount; + UINT64 FileSize; + UINTN LongestPath; + CHAR16 *CorrectedPath; + BOOLEAN FoundOne; + BOOLEAN HeaderPrinted; + EFI_TIME LocalTime; + + HeaderPrinted = FALSE; + FileCount = 0; + DirCount = 0; + FileSize = 0; + ListHead = NULL; + ShellStatus = SHELL_SUCCESS; + LongestPath = 0; + CorrectedPath = NULL; + + if (Found != NULL) { + FoundOne = *Found; + } else { + FoundOne = FALSE; + } + + CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, RootPath, 0); + if (CorrectedPath == NULL) { + return SHELL_OUT_OF_RESOURCES; + } + if (CorrectedPath[StrLen(CorrectedPath)-1] != L'\\' + &&CorrectedPath[StrLen(CorrectedPath)-1] != L'/') { + CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, L"\\", 0); + } + CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, SearchString, 0); + if (CorrectedPath == NULL) { + return (SHELL_OUT_OF_RESOURCES); + } + + PathCleanUpDirectories(CorrectedPath); + + Status = ShellOpenFileMetaArg((CHAR16*)CorrectedPath, EFI_FILE_MODE_READ, &ListHead); + if (!EFI_ERROR(Status)) { + if (ListHead == NULL || IsListEmpty(&ListHead->Link)) { + SHELL_FREE_NON_NULL(CorrectedPath); + return (SHELL_SUCCESS); + } + + if (Sfo && Found == NULL) { + PrintSfoVolumeInfoTableEntry(ListHead); + } + + if (!Sfo) { + // + // Sort the file list by FileName, stably. + // + // If the call below fails, then the EFI_SHELL_FILE_INFO list anchored to + // ListHead will not be changed in any way. + // + ShellSortFileList ( + &ListHead, + NULL, // Duplicates + ShellSortFileListByFileName + ); + } + + for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link), LongestPath = 0 + ; !IsNull(&ListHead->Link, &Node->Link) + ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link) + ){ + if (ShellGetExecutionBreakFlag ()) { + ShellStatus = SHELL_ABORTED; + break; + } + ASSERT(Node != NULL); + + // + // Change the file time to local time. + // + Status = gRT->GetTime(&LocalTime, NULL); + if (!EFI_ERROR (Status) && (LocalTime.TimeZone != EFI_UNSPECIFIED_TIMEZONE)) { + if ((Node->Info->CreateTime.TimeZone != EFI_UNSPECIFIED_TIMEZONE) && + (Node->Info->CreateTime.Month >= 1 && Node->Info->CreateTime.Month <= 12)) { + // + // FileTimeToLocalTime () requires Month is in a valid range, other buffer out-of-band access happens. + // + FileTimeToLocalTime (&Node->Info->CreateTime, LocalTime.TimeZone); + } + if ((Node->Info->LastAccessTime.TimeZone != EFI_UNSPECIFIED_TIMEZONE) && + (Node->Info->LastAccessTime.Month >= 1 && Node->Info->LastAccessTime.Month <= 12)) { + FileTimeToLocalTime (&Node->Info->LastAccessTime, LocalTime.TimeZone); + } + if ((Node->Info->ModificationTime.TimeZone != EFI_UNSPECIFIED_TIMEZONE) && + (Node->Info->ModificationTime.Month >= 1 && Node->Info->ModificationTime.Month <= 12)) { + FileTimeToLocalTime (&Node->Info->ModificationTime, LocalTime.TimeZone); + } + } + + if (LongestPath < StrSize(Node->FullName)) { + LongestPath = StrSize(Node->FullName); + } + ASSERT(Node->Info != NULL); + ASSERT((Node->Info->Attribute & EFI_FILE_VALID_ATTR) == Node->Info->Attribute); + if (Attribs == 0) { + // + // NOT system & NOT hidden + // + if ( (Node->Info->Attribute & EFI_FILE_SYSTEM) + || (Node->Info->Attribute & EFI_FILE_HIDDEN) + ){ + continue; + } + } else if ((Attribs != EFI_FILE_VALID_ATTR) || + (Count == 5)) { + // + // Only matches the bits which "Attribs" contains, not + // all files/directories with any of the bits. + // Count == 5 is used to tell the difference between a user + // specifying all bits (EX: -arhsda) and just specifying + // -a (means display all files with any attribute). + // + if ( (Node->Info->Attribute & Attribs) != Attribs) { + continue; + } + } + + if (!Sfo && !HeaderPrinted) { + PathRemoveLastItem (CorrectedPath); + PrintNonSfoHeader(CorrectedPath); + } + PrintFileInformation(Sfo, Node, &FileCount, &FileSize, &DirCount); + FoundOne = TRUE; + HeaderPrinted = TRUE; + } + + if (!Sfo && ShellStatus != SHELL_ABORTED && HeaderPrinted) { + PrintNonSfoFooter(FileCount, FileSize, DirCount); + } + } + + if (Rec && ShellStatus != SHELL_ABORTED) { + // + // Re-Open all the files under the starting path for directories that didnt necessarily match our file filter + // + ShellCloseFileMetaArg(&ListHead); + CorrectedPath[0] = CHAR_NULL; + CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, RootPath, 0); + if (CorrectedPath == NULL) { + return SHELL_OUT_OF_RESOURCES; + } + if (CorrectedPath[StrLen(CorrectedPath)-1] != L'\\' + &&CorrectedPath[StrLen(CorrectedPath)-1] != L'/') { + CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, L"\\", 0); + } + CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, L"*", 0); + Status = ShellOpenFileMetaArg((CHAR16*)CorrectedPath, EFI_FILE_MODE_READ, &ListHead); + + if (!EFI_ERROR(Status)) { + for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link) + ; !IsNull(&ListHead->Link, &Node->Link) && ShellStatus == SHELL_SUCCESS + ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link) + ){ + if (ShellGetExecutionBreakFlag ()) { + ShellStatus = SHELL_ABORTED; + break; + } + + // + // recurse on any directory except the traversing ones... + // + if (((Node->Info->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY) + && StrCmp(Node->FileName, L".") != 0 + && StrCmp(Node->FileName, L"..") != 0 + ){ + ShellStatus = PrintLsOutput( + Rec, + Attribs, + Sfo, + Node->FullName, + SearchString, + &FoundOne, + Count, + TimeZone, + FALSE); + + // + // Since it's running recursively, we have to break immediately when returned SHELL_ABORTED + // + if (ShellStatus == SHELL_ABORTED) { + break; + } + } + } + } + } + + SHELL_FREE_NON_NULL(CorrectedPath); + ShellCloseFileMetaArg(&ListHead); + + if (Found == NULL && !FoundOne) { + if (ListUnfiltered) { + // + // When running "ls" without any filtering request, avoid outputing + // "File not found" when the directory is entirely empty, but print + // header and footer stating "0 File(s), 0 Dir(s)". + // + if (!Sfo) { + PrintNonSfoHeader (RootPath); + if (ShellStatus != SHELL_ABORTED) { + PrintNonSfoFooter (FileCount, FileSize, DirCount); + } + } + } else { + return (SHELL_NOT_FOUND); + } + } + + if (Found != NULL) { + *Found = FoundOne; + } + + return (ShellStatus); +} + +STATIC CONST SHELL_PARAM_ITEM LsParamList[] = { + {L"-r", TypeFlag}, + {L"-a", TypeStart}, + {L"-sfo", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'ls' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunLs ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + CONST CHAR16 *Attribs; + SHELL_STATUS ShellStatus; + UINT64 RequiredAttributes; + CONST CHAR16 *PathName; + CONST CHAR16 *CurDir; + UINTN Count; + CHAR16 *FullPath; + UINTN Size; + EFI_TIME TheTime; + CHAR16 *SearchString; + BOOLEAN ListUnfiltered; + + Size = 0; + FullPath = NULL; + ProblemParam = NULL; + Attribs = NULL; + ShellStatus = SHELL_SUCCESS; + RequiredAttributes = 0; + PathName = NULL; + SearchString = NULL; + CurDir = NULL; + Count = 0; + ListUnfiltered = FALSE; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // Fix local copies of the protocol pointers + // + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (LsParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"ls", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } + + if (ShellCommandLineGetCount(Package) > 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"ls"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // check for -a + // + if (ShellCommandLineGetFlag(Package, L"-a")) { + for ( Attribs = ShellCommandLineGetValue(Package, L"-a") + ; Attribs != NULL && *Attribs != CHAR_NULL && ShellStatus == SHELL_SUCCESS + ; Attribs++ + ){ + switch (*Attribs) { + case L'a': + case L'A': + RequiredAttributes |= EFI_FILE_ARCHIVE; + Count++; + continue; + case L's': + case L'S': + RequiredAttributes |= EFI_FILE_SYSTEM; + Count++; + continue; + case L'h': + case L'H': + RequiredAttributes |= EFI_FILE_HIDDEN; + Count++; + continue; + case L'r': + case L'R': + RequiredAttributes |= EFI_FILE_READ_ONLY; + Count++; + continue; + case L'd': + case L'D': + RequiredAttributes |= EFI_FILE_DIRECTORY; + Count++; + continue; + default: + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ATTRIBUTE), gShellLevel2HiiHandle, L"ls", ShellCommandLineGetValue(Package, L"-a")); + ShellStatus = SHELL_INVALID_PARAMETER; + break; + } // switch + } // for loop + // + // if nothing is specified all are specified + // + if (RequiredAttributes == 0) { + RequiredAttributes = EFI_FILE_VALID_ATTR; + } + } // if -a present + if (ShellStatus == SHELL_SUCCESS) { + PathName = ShellCommandLineGetRawValue(Package, 1); + if (PathName == NULL) { + // + // Nothing specified... must start from current directory + // + CurDir = gEfiShellProtocol->GetCurDir(NULL); + if (CurDir == NULL) { + ShellStatus = SHELL_NOT_FOUND; + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"ls"); + } + ListUnfiltered = TRUE; + // + // Copy to the 2 strings for starting path and file search string + // + ASSERT(SearchString == NULL); + ASSERT(FullPath == NULL); + StrnCatGrow(&SearchString, NULL, L"*", 0); + StrnCatGrow(&FullPath, NULL, CurDir, 0); + Size = FullPath != NULL? StrSize(FullPath) : 0; + StrnCatGrow(&FullPath, &Size, L"\\", 0); + } else { + if (StrStr(PathName, L":") == NULL && gEfiShellProtocol->GetCurDir(NULL) == NULL) { + // + // If we got something and it doesnt have a fully qualified path, then we needed to have a CWD. + // + ShellStatus = SHELL_NOT_FOUND; + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"ls"); + } else { + // + // We got a valid fully qualified path or we have a CWD + // + ASSERT((FullPath == NULL && Size == 0) || (FullPath != NULL)); + if (StrStr(PathName, L":") == NULL) { + StrnCatGrow(&FullPath, &Size, gEfiShellProtocol->GetCurDir(NULL), 0); + if (FullPath == NULL) { + ShellCommandLineFreeVarList (Package); + return SHELL_OUT_OF_RESOURCES; + } + Size = FullPath != NULL? StrSize(FullPath) : 0; + StrnCatGrow(&FullPath, &Size, L"\\", 0); + } + StrnCatGrow(&FullPath, &Size, PathName, 0); + if (FullPath == NULL) { + ShellCommandLineFreeVarList (Package); + return SHELL_OUT_OF_RESOURCES; + } + + if (ShellIsDirectory(PathName) == EFI_SUCCESS) { + // + // is listing ends with a directory, then we list all files in that directory + // + ListUnfiltered = TRUE; + StrnCatGrow(&SearchString, NULL, L"*", 0); + } else { + // + // must split off the search part that applies to files from the end of the directory part + // + StrnCatGrow(&SearchString, NULL, FullPath, 0); + if (SearchString == NULL) { + FreePool (FullPath); + ShellCommandLineFreeVarList (Package); + return SHELL_OUT_OF_RESOURCES; + } + PathRemoveLastItem (FullPath); + CopyMem (SearchString, SearchString + StrLen (FullPath), StrSize (SearchString + StrLen (FullPath))); + } + } + } + Status = gRT->GetTime(&TheTime, NULL); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"ls", L"gRT->GetTime", Status); + TheTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE; + } + + if (ShellStatus == SHELL_SUCCESS) { + ShellStatus = PrintLsOutput( + ShellCommandLineGetFlag(Package, L"-r"), + RequiredAttributes, + ShellCommandLineGetFlag(Package, L"-sfo"), + FullPath, + SearchString, + NULL, + Count, + TheTime.TimeZone, + ListUnfiltered + ); + if (ShellStatus == SHELL_NOT_FOUND) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LS_FILE_NOT_FOUND), gShellLevel2HiiHandle, L"ls", FullPath); + } else if (ShellStatus == SHELL_INVALID_PARAMETER) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"ls", FullPath); + } else if (ShellStatus == SHELL_ABORTED) { + // + // Ignore aborting. + // + } else if (ShellStatus != SHELL_SUCCESS) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"ls", FullPath); + } + } + } + } + } + + // + // Free memory allocated + // + SHELL_FREE_NON_NULL(SearchString); + SHELL_FREE_NON_NULL(FullPath); + ShellCommandLineFreeVarList (Package); + + return (ShellStatus); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Map.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Map.c new file mode 100644 index 00000000..722f660e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Map.c @@ -0,0 +1,1296 @@ +/** @file + Main file for map shell level 2 command. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel2CommandsLib.h" +#include +#include +#include +#include +#include + +/** + Determine if a string has only numbers and letters. + + This is useful for such things as Map names which can only be letters and numbers. + + @param[in] String pointer to the string to analyze, + @param[in] Len Number of characters to analyze. + + @retval TRUE String has only numbers and letters + @retval FALSE String has at least one other character. +**/ +BOOLEAN +IsNumberLetterOnly( + IN CONST CHAR16 *String, + IN CONST UINTN Len + ) +{ + UINTN Count; + for (Count = 0 ; Count < Len && String != NULL && *String != CHAR_NULL ; String++,Count++) { + if (! ((*String >= L'a' && *String <= L'z') || + (*String >= L'A' && *String <= L'Z') || + (*String >= L'0' && *String <= L'9')) + ){ + return (FALSE); + } + } + return (TRUE); +} + +/** + Do a search in the Target delimited list. + + @param[in] List The list to seatch in. + @param[in] MetaTarget The item to search for. MetaMatching supported. + @param[out] FullName Optional pointer to an allocated buffer containing + the match. + @param[in] Meta TRUE to use MetaMatching. + @param[in] SkipTrailingNumbers TRUE to allow for numbers after the MetaTarget. + @param[in] Target The single character that delimits list + items (";" normally). +**/ +BOOLEAN +SearchList( + IN CONST CHAR16 *List, + IN CONST CHAR16 *MetaTarget, + OUT CHAR16 **FullName OPTIONAL, + IN CONST BOOLEAN Meta, + IN CONST BOOLEAN SkipTrailingNumbers, + IN CONST CHAR16 *Target + + ) +{ + CHAR16 *TempList; + CONST CHAR16 *ListWalker; + BOOLEAN Result; + CHAR16 *TempSpot; + + for (ListWalker = List , TempList = NULL + ; ListWalker != NULL && *ListWalker != CHAR_NULL + ; + ) { + TempList = StrnCatGrow(&TempList, NULL, ListWalker, 0); + ASSERT(TempList != NULL); + TempSpot = StrStr(TempList, Target); + if (TempSpot != NULL) { + *TempSpot = CHAR_NULL; + } + + while (SkipTrailingNumbers && (ShellIsDecimalDigitCharacter(TempList[StrLen(TempList)-1]) || TempList[StrLen(TempList)-1] == L':')) { + TempList[StrLen(TempList)-1] = CHAR_NULL; + } + + ListWalker = StrStr(ListWalker, Target); + while(ListWalker != NULL && *ListWalker == *Target) { + ListWalker++; + } + if (Meta) { + Result = gUnicodeCollation->MetaiMatch(gUnicodeCollation, (CHAR16*)TempList, (CHAR16*)MetaTarget); + } else { + Result = (BOOLEAN)(StrCmp(TempList, MetaTarget)==0); + } + if (Result) { + if (FullName != NULL) { + *FullName = TempList; + } else { + FreePool(TempList); + } + return (TRUE); + } + FreePool(TempList); + TempList = NULL; + } + + return (FALSE); +} + +/** + Determine what type of device is represented and return it's string. The + string is in allocated memory and must be callee freed. The HII is is listed below. + The actual string cannot be determined. + + @param[in] DevicePath The device to analyze. + + @retval STR_MAP_MEDIA_UNKNOWN The media type is unknown. + @retval STR_MAP_MEDIA_HARDDISK The media is a hard drive. + @retval STR_MAP_MEDIA_CDROM The media is a CD ROM. + @retval STR_MAP_MEDIA_FLOPPY The media is a floppy drive. +**/ +CHAR16* +GetDeviceMediaType ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + ACPI_HID_DEVICE_PATH *Acpi; + + // + // Parse the device path: + // Devicepath sub type mediatype + // MEDIA_HANRDDRIVE_DP -> Hard Disk + // MEDIA_CDROM_DP -> CD Rom + // Acpi.HID = 0X0604 -> Floppy + // + if (NULL == DevicePath) { + return HiiGetString(gShellLevel2HiiHandle, STRING_TOKEN(STR_MAP_MEDIA_UNKNOWN), NULL); + } + + for (;!IsDevicePathEndType (DevicePath) ;DevicePath = NextDevicePathNode (DevicePath)) { + if (DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) { + switch (DevicePathSubType (DevicePath)) { + case MEDIA_HARDDRIVE_DP: + return HiiGetString(gShellLevel2HiiHandle, STRING_TOKEN(STR_MAP_MEDIA_HARDDISK), NULL); + case MEDIA_CDROM_DP: + return HiiGetString(gShellLevel2HiiHandle, STRING_TOKEN(STR_MAP_MEDIA_CDROM), NULL); + } + } else if (DevicePathType (DevicePath) == ACPI_DEVICE_PATH) { + Acpi = (ACPI_HID_DEVICE_PATH *) DevicePath; + if (EISA_ID_TO_NUM (Acpi->HID) == 0x0604) { + return HiiGetString(gShellLevel2HiiHandle, STRING_TOKEN(STR_MAP_MEDIA_FLOPPY), NULL); + } + } + } + + return HiiGetString(gShellLevel2HiiHandle, STRING_TOKEN(STR_MAP_MEDIA_UNKNOWN), NULL); +} + +/** + Function to detemine if a handle has removable storage. + + @param[in] DevicePath DevicePath to test. + + @retval TRUE The handle has removable storage. + @retval FALSE The handle does not have removable storage. +**/ +BOOLEAN +IsRemoveableDevice ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + if (NULL == DevicePath) { + return FALSE; + } + + while (!IsDevicePathEndType (DevicePath)) { + if (DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) { + switch (DevicePathSubType (DevicePath)) { + case MSG_USB_DP: + case MSG_SCSI_DP: + return TRUE; + default: + return FALSE; + } + } + DevicePath = NextDevicePathNode (DevicePath); + } + return FALSE; +} + +/** + Function to detemine if a something on the map list matches. + + @param[in] MapList The pointer to the list to test. + @param[in] Specific The pointer to a specific name to test for. + @param[in] TypeString The pointer to the list of types. + @param[in] Normal Always show normal mappings. + @param[in] Consist Always show consistent mappings. + + @retval TRUE The map should be displayed. + @retval FALSE The map should not be displayed. +**/ +BOOLEAN +MappingListHasType( + IN CONST CHAR16 *MapList, + IN CONST CHAR16 *Specific, + IN CONST CHAR16 *TypeString, + IN CONST BOOLEAN Normal, + IN CONST BOOLEAN Consist + ) +{ + CHAR16 *NewSpecific; + RETURN_STATUS Status; + UINTN Length; + + // + // specific has priority + // + if (Specific != NULL) { + Length = StrLen (Specific); + // + // Allocate enough buffer for Specific and potential ":" + // + NewSpecific = AllocatePool ((Length + 2) * sizeof(CHAR16)); + if (NewSpecific == NULL){ + return FALSE; + } + StrCpyS (NewSpecific, Length + 2, Specific); + if (Specific[Length - 1] != L':') { + Status = StrnCatS(NewSpecific, Length + 2, L":", StrLen(L":")); + if (EFI_ERROR (Status)) { + FreePool(NewSpecific); + return FALSE; + } + } + + if (SearchList(MapList, NewSpecific, NULL, TRUE, FALSE, L";")) { + FreePool(NewSpecific); + return (TRUE); + } + FreePool(NewSpecific); + } + if ( Consist + && Specific == NULL + && (SearchList(MapList, L"HD*", NULL, TRUE, TRUE, L";") + ||SearchList(MapList, L"CD*", NULL, TRUE, TRUE, L";") + ||SearchList(MapList, L"F*", NULL, TRUE, TRUE, L";") + ||SearchList(MapList, L"FP*", NULL, TRUE, TRUE, L";"))){ + return (TRUE); + } + + if ( Normal + && Specific == NULL + && (SearchList(MapList, L"FS", NULL, FALSE, TRUE, L";") + ||SearchList(MapList, L"BLK", NULL, FALSE, TRUE, L";"))){ + return (TRUE); + } + + if (TypeString != NULL && SearchList(MapList, TypeString, NULL, TRUE, TRUE, L";")) { + return (TRUE); + } + return (FALSE); +} + + +/** + Display a single map line for device Handle if conditions are met. + + @param[in] Verbose TRUE to display (extra) verbose information. + @param[in] Consist TRUE to display consistent mappings. + @param[in] Normal TRUE to display normal (not consist) mappings. + @param[in] TypeString pointer to string of filter types. + @param[in] SFO TRUE to display output in Standard Output Format. + @param[in] Specific pointer to string for specific map to display. + @param[in] Handle The handle to display from. + + @retval EFI_SUCCESS The mapping was displayed. +**/ +EFI_STATUS +PerformSingleMappingDisplay( + IN CONST BOOLEAN Verbose, + IN CONST BOOLEAN Consist, + IN CONST BOOLEAN Normal, + IN CONST CHAR16 *TypeString, + IN CONST BOOLEAN SFO, + IN CONST CHAR16 *Specific OPTIONAL, + IN CONST EFI_HANDLE Handle + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevPath; + EFI_DEVICE_PATH_PROTOCOL *DevPathCopy; + CONST CHAR16 *MapList; + CHAR16 *CurrentName; + CHAR16 *MediaType; + CHAR16 *DevPathString; + CHAR16 *TempSpot; + CHAR16 *Alias; + UINTN TempLen; + BOOLEAN Removable; + CONST CHAR16 *TempSpot2; + + Alias = NULL; + TempSpot2 = NULL; + CurrentName = NULL; + DevPath = DevicePathFromHandle(Handle); + DevPathCopy = DevPath; + MapList = gEfiShellProtocol->GetMapFromDevicePath(&DevPathCopy); + if (MapList == NULL) { + return EFI_NOT_FOUND; + } + + if (!MappingListHasType(MapList, Specific, TypeString, Normal, Consist)){ + return EFI_NOT_FOUND; + } + + if (Normal || !Consist) { + // + // need the Normal here since people can use both on command line. otherwise unused. + // + + // + // Allocate a name + // + CurrentName = NULL; + CurrentName = StrnCatGrow(&CurrentName, 0, MapList, 0); + if (CurrentName == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + // + // Chop off the other names that become "Alias(s)" + // leaving just the normal name + // + TempSpot = StrStr(CurrentName, L";"); + if (TempSpot != NULL) { + *TempSpot = CHAR_NULL; + } + } else { + CurrentName = NULL; + + // + // Skip the first name. This is the standard name. + // + TempSpot = StrStr(MapList, L";"); + if (TempSpot != NULL) { + TempSpot++; + } + SearchList(TempSpot, L"HD*", &CurrentName, TRUE, FALSE, L";"); + if (CurrentName == NULL) { + SearchList(TempSpot, L"CD*", &CurrentName, TRUE, FALSE, L";"); + } + if (CurrentName == NULL) { + SearchList(TempSpot, L"FP*", &CurrentName, TRUE, FALSE, L";"); + } + if (CurrentName == NULL) { + SearchList(TempSpot, L"F*", &CurrentName, TRUE, FALSE, L";"); + } + if (CurrentName == NULL) { + // + // We didnt find anything, so just the first one in the list... + // + CurrentName = StrnCatGrow(&CurrentName, 0, MapList, 0); + if (CurrentName == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + TempSpot = StrStr(CurrentName, L";"); + if (TempSpot != NULL) { + *TempSpot = CHAR_NULL; + } + } else { + Alias = StrnCatGrow(&Alias, 0, MapList, 0); + if (Alias == NULL) { + return EFI_OUT_OF_RESOURCES; + } + TempSpot = StrStr(Alias, CurrentName); + if (TempSpot != NULL) { + TempSpot2 = StrStr(TempSpot, L";"); + if (TempSpot2 != NULL) { + TempSpot2++; // Move past ";" from CurrentName + CopyMem(TempSpot, TempSpot2, StrSize(TempSpot2)); + } else { + *TempSpot = CHAR_NULL; + } + } + if (Alias[StrLen(Alias)-1] == L';') { + Alias[StrLen(Alias)-1] = CHAR_NULL; + } + } + } + DevPathString = ConvertDevicePathToText(DevPath, TRUE, FALSE); + TempLen = StrLen(CurrentName); + if (!SFO) { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_MAP_ENTRY), + gShellLevel2HiiHandle, + CurrentName, + Alias!=NULL?Alias:(TempLen < StrLen(MapList)?MapList + TempLen+1:L""), + DevPathString + ); + if (Verbose) { + // + // also print handle, media type, removable (y/n), and current directory + // + MediaType = GetDeviceMediaType(DevPath); + if ((TypeString != NULL &&MediaType != NULL && StrStr(TypeString, MediaType) != NULL) || TypeString == NULL) { + Removable = IsRemoveableDevice(DevPath); + TempSpot2 = ShellGetCurrentDir(CurrentName); + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_MAP_ENTRY_VERBOSE), + gShellLevel2HiiHandle, + ConvertHandleToHandleIndex(Handle), + MediaType, + Removable?L"Yes":L"No", + TempSpot2 + ); + } + SHELL_FREE_NON_NULL(MediaType); + } + } else { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_MAP_SFO_MAPPINGS), + gShellLevel2HiiHandle, + CurrentName, + DevPathString, + Consist?L"":(TempLen < StrLen(MapList)?MapList + TempLen+1:L"") + ); + } + SHELL_FREE_NON_NULL(DevPathString); + SHELL_FREE_NON_NULL(CurrentName); + SHELL_FREE_NON_NULL(Alias); + return EFI_SUCCESS; +} + +/** + Delete Specific from the list of maps for device Handle. + + @param[in] Specific The name to delete. + @param[in] Handle The device to look on. + + @retval EFI_SUCCESS The delete was successful. + @retval EFI_NOT_FOUND Name was not a map on Handle. +**/ +EFI_STATUS +PerformSingleMappingDelete( + IN CONST CHAR16 *Specific, + IN CONST EFI_HANDLE Handle + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevPath; + EFI_DEVICE_PATH_PROTOCOL *DevPathCopy; + CONST CHAR16 *MapList; + CHAR16 *CurrentName; + + DevPath = DevicePathFromHandle(Handle); + DevPathCopy = DevPath; + MapList = gEfiShellProtocol->GetMapFromDevicePath(&DevPathCopy); + CurrentName = NULL; + + if (MapList == NULL) { + return (EFI_NOT_FOUND); + } + // + // if there is a specific and its not on the list... + // + if (!SearchList(MapList, Specific, &CurrentName, TRUE, FALSE, L";")) { + return (EFI_NOT_FOUND); + } + return (gEfiShellProtocol->SetMap(NULL, CurrentName)); +} + +CONST CHAR16 Cd[] = L"cd*"; +CONST CHAR16 Hd[] = L"hd*"; +CONST CHAR16 Fp[] = L"fp*"; +CONST CHAR16 AnyF[] = L"F*"; +/** + Function to display mapping information to the user. + + If Specific is specified then Consist and Normal will be ignored since information will + be printed for the specific item only. + + @param[in] Verbose TRUE to display (extra) verbose information. + @param[in] Consist TRUE to display consistent mappings. + @param[in] Normal TRUE to display normal (not consist) mappings. + @param[in] TypeString Pointer to string of filter types. + @param[in] SFO TRUE to display output in Standard Output Format. + @param[in] Specific Pointer to string for specific map to display. + @param[in] Header TRUE to print the header block. + + @retval SHELL_SUCCESS The display was printed. + @retval SHELL_INVALID_PARAMETER One of Consist or Normal must be TRUE if no Specific. + +**/ +SHELL_STATUS +PerformMappingDisplay( + IN CONST BOOLEAN Verbose, + IN CONST BOOLEAN Consist, + IN CONST BOOLEAN Normal, + IN CONST CHAR16 *TypeString, + IN CONST BOOLEAN SFO, + IN CONST CHAR16 *Specific OPTIONAL, + IN CONST BOOLEAN Header + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN BufferSize; + UINTN LoopVar; + CHAR16 *Test; + BOOLEAN Found; + + if (!Consist && !Normal && Specific == NULL && TypeString == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"map"); + return (SHELL_INVALID_PARAMETER); + } + + if (TypeString != NULL) { + Test = (CHAR16*)Cd; + if (StrnCmp(TypeString, Test, StrLen(Test)-1) != 0) { + Test = (CHAR16*)Hd; + if (StrnCmp(TypeString, Test, StrLen(Test)-1) != 0) { + Test = (CHAR16*)Fp; + if (StrnCmp(TypeString, Test, StrLen(Test)-1) != 0) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"map", TypeString); + return (SHELL_INVALID_PARAMETER); + } + } else if (Test == NULL) { + Test = (CHAR16*)AnyF; + } + } + } else { + Test = NULL; + } + + if (Header) { + // + // Print the header + // + if (!SFO) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MAP_HEADER), gShellLevel2HiiHandle); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_SFO_HEADER), gShellLevel2HiiHandle, L"map"); + } + } + + BufferSize = 0; + HandleBuffer = NULL; + + // + // Look up all SimpleFileSystems in the platform + // + Status = gBS->LocateHandle( + ByProtocol, + &gEfiSimpleFileSystemProtocolGuid, + NULL, + &BufferSize, + HandleBuffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + HandleBuffer = AllocateZeroPool(BufferSize); + if (HandleBuffer == NULL) { + return (SHELL_OUT_OF_RESOURCES); + } + Status = gBS->LocateHandle( + ByProtocol, + &gEfiSimpleFileSystemProtocolGuid, + NULL, + &BufferSize, + HandleBuffer); + } + + // + // Get the map name(s) for each one. + // + for ( LoopVar = 0, Found = FALSE + ; LoopVar < (BufferSize / sizeof(EFI_HANDLE)) && HandleBuffer != NULL + ; LoopVar ++ + ){ + Status = PerformSingleMappingDisplay( + Verbose, + Consist, + Normal, + Test, + SFO, + Specific, + HandleBuffer[LoopVar]); + if (!EFI_ERROR(Status)) { + Found = TRUE; + } + } + + // + // Look up all BlockIo in the platform + // + Status = gBS->LocateHandle( + ByProtocol, + &gEfiBlockIoProtocolGuid, + NULL, + &BufferSize, + HandleBuffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + SHELL_FREE_NON_NULL(HandleBuffer); + HandleBuffer = AllocateZeroPool(BufferSize); + if (HandleBuffer == NULL) { + return (SHELL_OUT_OF_RESOURCES); + } + Status = gBS->LocateHandle( + ByProtocol, + &gEfiBlockIoProtocolGuid, + NULL, + &BufferSize, + HandleBuffer); + } + if (!EFI_ERROR(Status) && HandleBuffer != NULL) { + // + // Get the map name(s) for each one. + // + for ( LoopVar = 0 + ; LoopVar < BufferSize / sizeof(EFI_HANDLE) + ; LoopVar ++ + ){ + // + // Skip any that were already done... + // + if (gBS->OpenProtocol( + HandleBuffer[LoopVar], + &gEfiSimpleFileSystemProtocolGuid, + NULL, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL) == EFI_SUCCESS) { + continue; + } + Status = PerformSingleMappingDisplay( + Verbose, + Consist, + Normal, + Test, + SFO, + Specific, + HandleBuffer[LoopVar]); + if (!EFI_ERROR(Status)) { + Found = TRUE; + } + } + FreePool(HandleBuffer); + } + if (!Found) { + if (Specific != NULL) { + ShellPrintHiiEx(gST->ConOut->Mode->CursorColumn, gST->ConOut->Mode->CursorRow-1, NULL, STRING_TOKEN (STR_MAP_NF), gShellLevel2HiiHandle, L"map", Specific); + } else { + ShellPrintHiiEx(gST->ConOut->Mode->CursorColumn, gST->ConOut->Mode->CursorRow-1, NULL, STRING_TOKEN (STR_CD_NF), gShellLevel2HiiHandle, L"map"); + } + } + return (SHELL_SUCCESS); +} + +/** + Perform a mapping display and parse for multiple types in the TypeString. + + @param[in] Verbose TRUE to use verbose output. + @param[in] Consist TRUE to display consistent names. + @param[in] Normal TRUE to display normal names. + @param[in] TypeString An optional comma-delimited list of types. + @param[in] SFO TRUE to display in SFO format. See Spec. + @param[in] Specific An optional specific map name to display alone. + + @retval SHELL_INVALID_PARAMETER A parameter was invalid. + @retval SHELL_SUCCESS The display was successful. + @sa PerformMappingDisplay +**/ +SHELL_STATUS +PerformMappingDisplay2( + IN CONST BOOLEAN Verbose, + IN CONST BOOLEAN Consist, + IN CONST BOOLEAN Normal, + IN CONST CHAR16 *TypeString, + IN CONST BOOLEAN SFO, + IN CONST CHAR16 *Specific OPTIONAL + ) +{ + CONST CHAR16 *TypeWalker; + SHELL_STATUS ShellStatus; + CHAR16 *Comma; + + + if (TypeString == NULL) { + return (PerformMappingDisplay(Verbose, Consist, Normal, NULL, SFO, Specific, TRUE)); + } + ShellStatus = SHELL_SUCCESS; + for (TypeWalker = TypeString ; TypeWalker != NULL && *TypeWalker != CHAR_NULL ;) { + Comma = StrStr(TypeWalker, L","); + if (Comma == NULL) { + if (ShellStatus == SHELL_SUCCESS) { + ShellStatus = PerformMappingDisplay(Verbose, Consist, Normal, TypeWalker, SFO, Specific, (BOOLEAN)(TypeWalker == TypeString)); + } else { + PerformMappingDisplay(Verbose, Consist, Normal, TypeWalker, SFO, Specific, (BOOLEAN)(TypeWalker == TypeString)); + } + break; + } else { + *Comma = CHAR_NULL; + if (ShellStatus == SHELL_SUCCESS) { + ShellStatus = PerformMappingDisplay(Verbose, Consist, Normal, TypeWalker, SFO, Specific, (BOOLEAN)(TypeWalker == TypeString)); + } else { + PerformMappingDisplay(Verbose, Consist, Normal, TypeWalker, SFO, Specific, (BOOLEAN)(TypeWalker == TypeString)); + } + *Comma = L','; + TypeWalker = Comma + 1; + } + } + + return (ShellStatus); +} + +/** + Delete a specific map. + + @param[in] Specific The pointer to the name of the map to delete. + + @retval EFI_INVALID_PARAMETER Specific was NULL. + @retval EFI_SUCCESS The operation was successful. + @retval EFI_NOT_FOUND Specific could not be found. +**/ +EFI_STATUS +PerformMappingDelete( + IN CONST CHAR16 *Specific + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN BufferSize; + UINTN LoopVar; + BOOLEAN Deleted; + + if (Specific == NULL) { + return (EFI_INVALID_PARAMETER); + } + + BufferSize = 0; + HandleBuffer = NULL; + Deleted = FALSE; + + // + // Look up all SimpleFileSystems in the platform + // + Status = gBS->LocateHandle( + ByProtocol, + &gEfiDevicePathProtocolGuid, + NULL, + &BufferSize, + HandleBuffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + HandleBuffer = AllocateZeroPool(BufferSize); + if (HandleBuffer == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + Status = gBS->LocateHandle( + ByProtocol, + &gEfiDevicePathProtocolGuid, + NULL, + &BufferSize, + HandleBuffer); + } + if (EFI_ERROR(Status)) { + SHELL_FREE_NON_NULL(HandleBuffer); + return (Status); + } + + if (HandleBuffer != NULL) { + // + // Get the map name(s) for each one. + // + for ( LoopVar = 0 + ; LoopVar < BufferSize / sizeof(EFI_HANDLE) + ; LoopVar ++ + ){ + if (PerformSingleMappingDelete(Specific,HandleBuffer[LoopVar]) == SHELL_SUCCESS) { + Deleted = TRUE; + } + } + } + // + // Look up all BlockIo in the platform + // + Status = gBS->LocateHandle( + ByProtocol, + &gEfiBlockIoProtocolGuid, + NULL, + &BufferSize, + HandleBuffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + FreePool(HandleBuffer); + HandleBuffer = AllocateZeroPool(BufferSize); + if (HandleBuffer == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + Status = gBS->LocateHandle( + ByProtocol, + &gEfiBlockIoProtocolGuid, + NULL, + &BufferSize, + HandleBuffer); + } + if (EFI_ERROR(Status)) { + SHELL_FREE_NON_NULL(HandleBuffer); + return (Status); + } + + if (HandleBuffer != NULL) { + // + // Get the map name(s) for each one. + // + for ( LoopVar = 0 + ; LoopVar < BufferSize / sizeof(EFI_HANDLE) + ; LoopVar ++ + ){ + // + // Skip any that were already done... + // + if (gBS->OpenProtocol( + HandleBuffer[LoopVar], + &gEfiDevicePathProtocolGuid, + NULL, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL) == EFI_SUCCESS) { + continue; + } + if (PerformSingleMappingDelete(Specific,HandleBuffer[LoopVar]) == SHELL_SUCCESS) { + Deleted = TRUE; + } + } + } + SHELL_FREE_NON_NULL(HandleBuffer); + if (!Deleted) { + return (EFI_NOT_FOUND); + } + return (EFI_SUCCESS); +} + +/** + function to add a mapping from mapping. + + This function will get the device path associated with the mapping and call SetMap. + + @param[in] Map The Map to add a mapping for + @param[in] SName The name of the new mapping + + @retval SHELL_SUCCESS the mapping was added + @retval SHELL_INVALID_PARAMETER the device path for Map could not be retrieved. + @return Shell version of a return value from EfiShellProtocol->SetMap + +**/ +SHELL_STATUS +AddMappingFromMapping( + IN CONST CHAR16 *Map, + IN CONST CHAR16 *SName + ) +{ + CONST EFI_DEVICE_PATH_PROTOCOL *DevPath; + EFI_STATUS Status; + CHAR16 *NewSName; + RETURN_STATUS StrRetStatus; + + NewSName = AllocateCopyPool(StrSize(SName) + sizeof(CHAR16), SName); + if (NewSName == NULL) { + return (SHELL_OUT_OF_RESOURCES); + } + if (NewSName[StrLen(NewSName)-1] != L':') { + StrRetStatus = StrnCatS(NewSName, (StrSize(SName) + sizeof(CHAR16))/sizeof(CHAR16), L":", StrLen(L":")); + if (EFI_ERROR(StrRetStatus)) { + FreePool(NewSName); + return ((SHELL_STATUS) (StrRetStatus & (~MAX_BIT))); + } + } + + if (!IsNumberLetterOnly(NewSName, StrLen(NewSName)-1)) { + FreePool(NewSName); + return (SHELL_INVALID_PARAMETER); + } + + DevPath = gEfiShellProtocol->GetDevicePathFromMap(Map); + if (DevPath == NULL) { + FreePool(NewSName); + return (SHELL_INVALID_PARAMETER); + } + + Status = gEfiShellProtocol->SetMap(DevPath, NewSName); + FreePool(NewSName); + if (EFI_ERROR(Status)) { + return (SHELL_DEVICE_ERROR); + } + return (SHELL_SUCCESS); +} + +/** + function to add a mapping from an EFI_HANDLE. + + This function will get the device path associated with the Handle and call SetMap. + + @param[in] Handle The handle to add a mapping for + @param[in] SName The name of the new mapping + + @retval SHELL_SUCCESS the mapping was added + @retval SHELL_INVALID_PARAMETER SName was not valid for a map name. + @return Shell version of a return value from either + gBS->OpenProtocol or EfiShellProtocol->SetMap + +**/ +SHELL_STATUS +AddMappingFromHandle( + IN CONST EFI_HANDLE Handle, + IN CONST CHAR16 *SName + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevPath; + EFI_STATUS Status; + CHAR16 *NewSName; + RETURN_STATUS StrRetStatus; + + NewSName = AllocateCopyPool(StrSize(SName) + sizeof(CHAR16), SName); + if (NewSName == NULL) { + return (SHELL_OUT_OF_RESOURCES); + } + if (NewSName[StrLen(NewSName)-1] != L':') { + StrRetStatus = StrnCatS(NewSName, (StrSize(SName) + sizeof(CHAR16))/sizeof(CHAR16), L":", StrLen(L":")); + if (EFI_ERROR(StrRetStatus)) { + FreePool(NewSName); + return ((SHELL_STATUS) (StrRetStatus & (~MAX_BIT))); + } + } + + if (!IsNumberLetterOnly(NewSName, StrLen(NewSName)-1)) { + FreePool(NewSName); + return (SHELL_INVALID_PARAMETER); + } + + Status = gBS->OpenProtocol( + Handle, + &gEfiDevicePathProtocolGuid, + (VOID**)&DevPath, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR(Status)) { + FreePool(NewSName); + return (SHELL_DEVICE_ERROR); + } + Status = gEfiShellProtocol->SetMap(DevPath, NewSName); + FreePool(NewSName); + if (EFI_ERROR(Status)) { + return (SHELL_DEVICE_ERROR); + } + return (SHELL_SUCCESS); +} + +STATIC CONST SHELL_PARAM_ITEM MapParamList[] = { + {L"-d", TypeValue}, + {L"-r", TypeFlag}, + {L"-v", TypeFlag}, + {L"-c", TypeFlag}, + {L"-f", TypeFlag}, + {L"-u", TypeFlag}, + {L"-t", TypeValue}, + {L"-sfo", TypeValue}, + {NULL, TypeMax} + }; + +/** + The routine issues dummy read for every physical block device to cause + the BlockIo re-installed if media change happened. +**/ +VOID +ProbeForMediaChange ( + VOID + ) +{ + EFI_STATUS Status; + UINTN HandleCount; + EFI_HANDLE *Handles; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + UINTN Index; + + gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiBlockIoProtocolGuid, + NULL, + &HandleCount, + &Handles + ); + // + // Probe for media change for every physical block io + // + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol ( + Handles[Index], + &gEfiBlockIoProtocolGuid, + (VOID **) &BlockIo + ); + if (!EFI_ERROR (Status)) { + if (!BlockIo->Media->LogicalPartition) { + // + // Per spec: + // The function (ReadBlocks) must return EFI_NO_MEDIA or + // EFI_MEDIA_CHANGED even if LBA, BufferSize, or Buffer are invalid so the caller can probe + // for changes in media state. + // + BlockIo->ReadBlocks ( + BlockIo, + BlockIo->Media->MediaId, + 0, + 0, + NULL + ); + } + } + } +} + +/** + Function for 'map' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunMap ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + CONST CHAR16 *SName; + CONST CHAR16 *Mapping; + EFI_HANDLE MapAsHandle; + SHELL_STATUS ShellStatus; + BOOLEAN SfoMode; + BOOLEAN ConstMode; + BOOLEAN NormlMode; + CONST CHAR16 *Param1; + CONST CHAR16 *TypeString; + UINTN TempStringLength; + + ProblemParam = NULL; + Mapping = NULL; + SName = NULL; + ShellStatus = SHELL_SUCCESS; + MapAsHandle = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (MapParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"map", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + SfoMode = ShellCommandLineGetFlag(Package, L"-sfo"); + ConstMode = ShellCommandLineGetFlag(Package, L"-c"); + NormlMode = ShellCommandLineGetFlag(Package, L"-f"); + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } else if (ShellCommandLineGetRawValue(Package, 3) != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"map"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // Deleting a map name... + // + if (ShellCommandLineGetFlag(Package, L"-d")) { + if ( ShellCommandLineGetFlag(Package, L"-r") + || ShellCommandLineGetFlag(Package, L"-v") + || ConstMode + || NormlMode + || ShellCommandLineGetFlag(Package, L"-u") + || ShellCommandLineGetFlag(Package, L"-t") + ){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CON), gShellLevel2HiiHandle, L"map"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + SName = ShellCommandLineGetValue(Package, L"-d"); + if (SName != NULL) { + Status = PerformMappingDelete(SName); + if (EFI_ERROR(Status)) { + if (Status == EFI_ACCESS_DENIED) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellLevel2HiiHandle, L"map"); + ShellStatus = SHELL_ACCESS_DENIED; + } else if (Status == EFI_NOT_FOUND) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MAP_NF), gShellLevel2HiiHandle, L"map", SName); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, L"map", Status); + ShellStatus = SHELL_UNSUPPORTED; + } + } + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"map"); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } + } else if ( ShellCommandLineGetFlag(Package, L"-r") +// || ShellCommandLineGetFlag(Package, L"-v") + || ConstMode + || NormlMode + || ShellCommandLineGetFlag(Package, L"-u") + || ShellCommandLineGetFlag(Package, L"-t") + ){ + ProbeForMediaChange (); + if ( ShellCommandLineGetFlag(Package, L"-r")) { + // + // Do the reset + // + Status = ShellCommandCreateInitialMappingsAndPaths(); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, L"map", Status); + ShellStatus = SHELL_UNSUPPORTED; + } + } + if ( ShellStatus == SHELL_SUCCESS && ShellCommandLineGetFlag(Package, L"-u")) { + // + // Do the Update + // + Status = ShellCommandUpdateMapping (); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, L"map", Status); + ShellStatus = SHELL_UNSUPPORTED; + } + } + if (ShellStatus == SHELL_SUCCESS) { + Param1 = ShellCommandLineGetRawValue(Package, 1); + TypeString = ShellCommandLineGetValue(Package, L"-t"); + if (!ConstMode + &&!NormlMode + &&TypeString == NULL + ) { + // + // now do the display... + // + ShellStatus = PerformMappingDisplay( + ShellCommandLineGetFlag(Package, L"-v"), + TRUE, + TRUE, + NULL, + SfoMode, + Param1, + TRUE + ); + } else { + // + // now do the display... + // + ShellStatus = PerformMappingDisplay2( + ShellCommandLineGetFlag(Package, L"-v"), + ConstMode, + NormlMode, + TypeString, + SfoMode, + Param1 + ); + } + } + } else { + // + // adding or displaying (there were no flags) + // + SName = ShellCommandLineGetRawValue(Package, 1); + Mapping = ShellCommandLineGetRawValue(Package, 2); + if ( SName == NULL + && Mapping == NULL + ){ + // + // display only since no flags + // + ShellStatus = PerformMappingDisplay( + ShellCommandLineGetFlag(Package, L"-v"), + TRUE, + TRUE, + NULL, + SfoMode, + NULL, + TRUE + ); + } else if ( SName == NULL + || Mapping == NULL + ){ + // + // Display only the one specified + // + ShellStatus = PerformMappingDisplay( + FALSE, + FALSE, + FALSE, + NULL, + SfoMode, + SName, // note the variable here... + TRUE + ); + } else { + if (ShellIsHexOrDecimalNumber(Mapping, TRUE, FALSE)) { + MapAsHandle = ConvertHandleIndexToHandle(ShellStrToUintn(Mapping)); + } else { + MapAsHandle = NULL; + } + if (MapAsHandle == NULL && Mapping[StrLen(Mapping)-1] != L':') { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"map", Mapping); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + TempStringLength = StrLen(SName); + if (!IsNumberLetterOnly(SName, TempStringLength-(SName[TempStringLength-1]==L':'?1:0))) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"map", SName); + ShellStatus = SHELL_INVALID_PARAMETER; + } + + if (ShellStatus == SHELL_SUCCESS) { + if (MapAsHandle != NULL) { + ShellStatus = AddMappingFromHandle(MapAsHandle, SName); + } else { + ShellStatus = AddMappingFromMapping(Mapping, SName); + } + + if (ShellStatus != SHELL_SUCCESS) { + switch (ShellStatus) { + case SHELL_ACCESS_DENIED: + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellLevel2HiiHandle, L"map"); + break; + case SHELL_INVALID_PARAMETER: + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"map", Mapping); + break; + case SHELL_DEVICE_ERROR: + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MAP_NOF), gShellLevel2HiiHandle, L"map", Mapping); + break; + default: + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, L"map", ShellStatus|MAX_BIT); + } + } else { + // + // now do the display... + // + ShellStatus = PerformMappingDisplay( + FALSE, + FALSE, + FALSE, + NULL, + SfoMode, + SName, + TRUE + ); + } // we were sucessful so do an output + } + } // got a valid map target + } // got 2 variables + } // we are adding a mapping + } // got valid parameters + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + + return (ShellStatus); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/MkDir.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/MkDir.c new file mode 100644 index 00000000..411ed280 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/MkDir.c @@ -0,0 +1,161 @@ +/** @file + Main file for attrib shell level 2 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel2CommandsLib.h" + +/** + Function for 'mkdir' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunMkDir ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + CONST CHAR16 *NewDirName; + CHAR16 *NewDirNameCopy; + CHAR16 *SplitName; + CHAR16 SaveSplitChar; + UINTN DirCreateCount; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_FILE_HANDLE FileHandle; + SHELL_STATUS ShellStatus; + + ShellStatus = SHELL_SUCCESS; + NewDirNameCopy = NULL; + SplitName = NULL; + SaveSplitChar = CHAR_NULL; + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"mkdir", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } + + // + // create a set of directories + // + if (ShellCommandLineGetRawValue(Package, 1) == NULL) { + // + // we didnt get a single parameter + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"mkdir"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + for ( DirCreateCount = 1 + ; + ; DirCreateCount++ + ){ + // + // loop through each directory specified + // + + NewDirName = ShellCommandLineGetRawValue(Package, DirCreateCount); + if (NewDirName == NULL) { + break; + } + // + // check if that already exists... if yes fail + // + FileHandle = NULL; + Status = ShellOpenFileByName(NewDirName, + &FileHandle, + EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, + EFI_FILE_DIRECTORY + ); + if (!EFI_ERROR(Status)) { + ShellCloseFile(&FileHandle); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MKDIR_ALREADY), gShellLevel2HiiHandle, NewDirName); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FileHandle == NULL); + // + // create the nested directory from parent to child. + // if NewDirName = test1\test2\test3, first create "test1\" directory, then "test1\test2\", finally "test1\test2\test3". + // + NewDirNameCopy = AllocateCopyPool (StrSize(NewDirName), NewDirName); + NewDirNameCopy = PathCleanUpDirectories (NewDirNameCopy); + if(NewDirNameCopy == NULL) { + ShellStatus = SHELL_OUT_OF_RESOURCES; + break; + } + SplitName = NewDirNameCopy; + while (SplitName != NULL) { + SplitName = StrStr (SplitName + 1, L"\\"); + if (SplitName != NULL) { + SaveSplitChar = *(SplitName + 1); + *(SplitName + 1) = '\0'; + } + // + // check if current nested directory already exists... continue to create the child directory. + // + Status = ShellOpenFileByName (NewDirNameCopy, + &FileHandle, + EFI_FILE_MODE_READ, + EFI_FILE_DIRECTORY + ); + if (!EFI_ERROR(Status)) { + ShellCloseFile (&FileHandle); + } else { + Status = ShellCreateDirectory (NewDirNameCopy, &FileHandle); + if (EFI_ERROR(Status)) { + break; + } + if (FileHandle != NULL) { + gEfiShellProtocol->CloseFile (FileHandle); + } + } + if (SplitName != NULL) { + *(SplitName + 1) = SaveSplitChar; + } + } + if (EFI_ERROR(Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MKDIR_CREATEFAIL), gShellLevel2HiiHandle, NewDirName); + ShellStatus = SHELL_ACCESS_DENIED; + break; + } + SHELL_FREE_NON_NULL (NewDirNameCopy); + } + } + } + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + + return (ShellStatus); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c new file mode 100644 index 00000000..51dec67c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c @@ -0,0 +1,860 @@ +/** @file + Main file for mv shell level 2 function. + + (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel2CommandsLib.h" + +/** + function to determine if a move is between file systems. + + @param FullName [in] The name of the file to move. + @param Cwd [in] The current working directory + @param DestPath [in] The target location to move to + + @retval TRUE The move is across file system. + @retval FALSE The move is within a file system. +**/ +BOOLEAN +IsBetweenFileSystem( + IN CONST CHAR16 *FullName, + IN CONST CHAR16 *Cwd, + IN CONST CHAR16 *DestPath + ) +{ + CHAR16 *Test; + CHAR16 *Test1; + UINTN Result; + + Test = StrStr(FullName, L":"); + if (Test == NULL && Cwd != NULL) { + Test = StrStr(Cwd, L":"); + } + Test1 = StrStr(DestPath, L":"); + if (Test1 == NULL && Cwd != NULL) { + Test1 = StrStr(Cwd, L":"); + } + if (Test1 != NULL && Test != NULL) { + *Test = CHAR_NULL; + *Test1 = CHAR_NULL; + Result = StringNoCaseCompare(&FullName, &DestPath); + *Test = L':'; + *Test1 = L':'; + if (Result != 0) { + return (TRUE); + } + } + return (FALSE); +} + +/** + function to determine if SrcPath is valid to mv. + + if SrcPath equal CWD then it's invalid. + if SrcPath is the parent path of CWD then it's invalid. + is SrcPath is NULL return FALSE. + + if CwdPath is NULL then ASSERT() + + @param SrcPath [in] The source path. + @param CwdPath [in] The current working directory. + + @retval TRUE The source path is valid. + @retval FALSE The source path is invalid. +**/ +BOOLEAN +IsSoucePathValid( + IN CONST CHAR16* SrcPath, + IN CONST CHAR16* CwdPath + ) +{ + CHAR16* SrcPathBuffer; + CHAR16* CwdPathBuffer; + BOOLEAN Ret; + + ASSERT (CwdPath != NULL); + if (SrcPath == NULL) { + return FALSE; + } + + Ret = TRUE; + + SrcPathBuffer = AllocateCopyPool (StrSize (SrcPath), SrcPath); + if (SrcPathBuffer == NULL) { + return FALSE; + } + + CwdPathBuffer = AllocateCopyPool (StrSize (CwdPath), CwdPath); + if (CwdPathBuffer == NULL) { + FreePool(SrcPathBuffer); + return FALSE; + } + + gUnicodeCollation->StrUpr (gUnicodeCollation, SrcPathBuffer); + gUnicodeCollation->StrUpr (gUnicodeCollation, CwdPathBuffer); + + if (SrcPathBuffer[StrLen (SrcPathBuffer) -1 ] == L'\\') { + SrcPathBuffer[StrLen (SrcPathBuffer) - 1] = CHAR_NULL; + } + + if (CwdPathBuffer[StrLen (CwdPathBuffer) - 1] == L'\\') { + CwdPathBuffer[StrLen (CwdPathBuffer) - 1] = CHAR_NULL; + } + + if (StrCmp (CwdPathBuffer, SrcPathBuffer) == 0 || + ((StrStr (CwdPathBuffer, SrcPathBuffer) == CwdPathBuffer) && + (CwdPathBuffer[StrLen (SrcPathBuffer)] == L'\\')) + ) { + Ret = FALSE; + } + + FreePool (SrcPathBuffer); + FreePool (CwdPathBuffer); + + return Ret; +} + +/** + Function to validate that moving a specific file (FileName) to a specific + location (DestPath) is valid. + + This function will verify that the destination is not a subdirectory of + FullName, that the Current working Directory is not being moved, and that + the directory is not read only. + + if the move is invalid this function will report the error to StdOut. + + @param SourcePath [in] The name of the file to move. + @param Cwd [in] The current working directory + @param DestPath [in] The target location to move to + @param Attribute [in] The Attribute of the file + @param DestAttr [in] The Attribute of the destination + @param FileStatus [in] The Status of the file when opened + + @retval TRUE The move is valid + @retval FALSE The move is not +**/ +BOOLEAN +IsValidMove( + IN CONST CHAR16 *SourcePath, + IN CONST CHAR16 *Cwd, + IN CONST CHAR16 *DestPath, + IN CONST UINT64 Attribute, + IN CONST UINT64 DestAttr, + IN CONST EFI_STATUS FileStatus + ) +{ + CHAR16 *DestPathCopy; + CHAR16 *DestPathWalker; + + if ((Cwd != NULL) && ((Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY)) { + if (!IsSoucePathValid (SourcePath, Cwd)) { + // + // Invalid move + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_MV_INV_CWD), gShellLevel2HiiHandle); + return FALSE; + } + } + + // + // invalid to move read only or move to a read only destination + // + if (((Attribute & EFI_FILE_READ_ONLY) != 0) + || (FileStatus == EFI_WRITE_PROTECTED) + || ((DestAttr & EFI_FILE_READ_ONLY) != 0) + ) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_RO), gShellLevel2HiiHandle, SourcePath); + return (FALSE); + } + + DestPathCopy = AllocateCopyPool(StrSize(DestPath), DestPath); + if (DestPathCopy == NULL) { + return (FALSE); + } + + for (DestPathWalker = DestPathCopy; *DestPathWalker == L'\\'; DestPathWalker++) ; + + while(DestPathWalker != NULL && DestPathWalker[StrLen(DestPathWalker)-1] == L'\\') { + DestPathWalker[StrLen(DestPathWalker)-1] = CHAR_NULL; + } + + ASSERT(DestPathWalker != NULL); + ASSERT(SourcePath != NULL); + + // + // If they're the same, or if source is "above" dest on file path tree + // + if ( StringNoCaseCompare (&DestPathWalker, &SourcePath) == 0 || + ((StrStr(DestPathWalker, SourcePath) == DestPathWalker) && + (DestPathWalker[StrLen(SourcePath)] == '\\') + ) + ) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_SUB), gShellLevel2HiiHandle); + FreePool(DestPathCopy); + return (FALSE); + } + FreePool(DestPathCopy); + + return (TRUE); +} + +/** + Function to take a destination path that might contain wildcards and verify + that there is only a single possible target (IE we cant have wildcards that + have 2 possible destination). + + if the result is sucessful the caller must free *DestPathPointer. + + @param[in] DestParameter The original path to the destination. + @param[in, out] DestPathPointer A pointer to the callee allocated final path. + @param[in] Cwd A pointer to the current working directory. + @param[in] SingleSource TRUE to have only one source file. + @param[in, out] DestAttr A pointer to the destination information attribute. + + @retval SHELL_INVALID_PARAMETER The DestParameter could not be resolved to a location. + @retval SHELL_INVALID_PARAMETER The DestParameter could be resolved to more than 1 location. + @retval SHELL_INVALID_PARAMETER Cwd is required and is NULL. + @retval SHELL_SUCCESS The operation was sucessful. +**/ +SHELL_STATUS +GetDestinationLocation( + IN CONST CHAR16 *DestParameter, + IN OUT CHAR16 **DestPathPointer, + IN CONST CHAR16 *Cwd, + IN CONST BOOLEAN SingleSource, + IN OUT UINT64 *DestAttr + ) +{ + EFI_SHELL_FILE_INFO *DestList; + EFI_SHELL_FILE_INFO *Node; + CHAR16 *DestPath; + UINTN NewSize; + UINTN CurrentSize; + + DestList = NULL; + DestPath = NULL; + + ASSERT(DestAttr != NULL); + + if (StrStr(DestParameter, L"\\") == DestParameter) { + if (Cwd == NULL) { + return SHELL_INVALID_PARAMETER; + } + DestPath = AllocateZeroPool(StrSize(Cwd)); + if (DestPath == NULL) { + return (SHELL_OUT_OF_RESOURCES); + } + StrCpyS(DestPath, StrSize(Cwd) / sizeof(CHAR16), Cwd); + while (PathRemoveLastItem(DestPath)) ; + + // + // Append DestParameter beyond '\' which may be present + // + CurrentSize = StrSize(DestPath); + StrnCatGrow(&DestPath, &CurrentSize, &DestParameter[1], 0); + + *DestPathPointer = DestPath; + return (SHELL_SUCCESS); + } + // + // get the destination path + // + ShellOpenFileMetaArg((CHAR16*)DestParameter, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ|EFI_FILE_MODE_CREATE, &DestList); + if (DestList == NULL || IsListEmpty(&DestList->Link)) { + // + // Not existing... must be renaming + // + if (StrStr(DestParameter, L":") == NULL) { + if (Cwd == NULL) { + ShellCloseFileMetaArg(&DestList); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle); + return (SHELL_INVALID_PARAMETER); + } + NewSize = StrSize(Cwd); + NewSize += StrSize(DestParameter); + DestPath = AllocateZeroPool(NewSize); + if (DestPath == NULL) { + ShellCloseFileMetaArg(&DestList); + return (SHELL_OUT_OF_RESOURCES); + } + StrCpyS(DestPath, NewSize / sizeof(CHAR16), Cwd); + if (DestPath[StrLen(DestPath)-1] != L'\\' && DestParameter[0] != L'\\') { + StrCatS(DestPath, NewSize / sizeof(CHAR16), L"\\"); + } else if (DestPath[StrLen(DestPath)-1] == L'\\' && DestParameter[0] == L'\\') { + ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL; + } + StrCatS(DestPath, NewSize / sizeof(CHAR16), DestParameter); + } else { + ASSERT(DestPath == NULL); + DestPath = StrnCatGrow(&DestPath, NULL, DestParameter, 0); + if (DestPath == NULL) { + ShellCloseFileMetaArg(&DestList); + return (SHELL_OUT_OF_RESOURCES); + } + } + } else { + Node = (EFI_SHELL_FILE_INFO*)GetFirstNode(&DestList->Link); + *DestAttr = Node->Info->Attribute; + // + // Make sure there is only 1 node in the list. + // + if (!IsNodeAtEnd(&DestList->Link, &Node->Link)) { + ShellCloseFileMetaArg(&DestList); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, L"mv", DestParameter); + return (SHELL_INVALID_PARAMETER); + } + + // + // If we are a directory or a single file, then one node is fine. + // + if (ShellIsDirectory(Node->FullName)==EFI_SUCCESS || SingleSource) { + DestPath = AllocateZeroPool(StrSize(Node->FullName)+sizeof(CHAR16)); + if (DestPath == NULL) { + ShellCloseFileMetaArg(&DestList); + return (SHELL_OUT_OF_RESOURCES); + } + StrCpyS(DestPath, (StrSize(Node->FullName)+sizeof(CHAR16)) / sizeof(CHAR16), Node->FullName); + StrCatS(DestPath, (StrSize(Node->FullName)+sizeof(CHAR16)) / sizeof(CHAR16), L"\\"); + } else { + // + // cant move multiple files onto a single file. + // + ShellCloseFileMetaArg(&DestList); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_ERROR), gShellLevel2HiiHandle, L"mv", DestParameter); + return (SHELL_INVALID_PARAMETER); + } + } + + *DestPathPointer = DestPath; + ShellCloseFileMetaArg(&DestList); + + return (SHELL_SUCCESS); +} + +/** + Function to do a move across file systems. + + @param[in] Node A pointer to the file to be removed. + @param[in] DestPath A pointer to the destination file path. + @param[out] Resp A pointer to response from question. Pass back on looped calling + + @retval SHELL_SUCCESS The source file was moved to the destination. +**/ +EFI_STATUS +MoveBetweenFileSystems( + IN EFI_SHELL_FILE_INFO *Node, + IN CONST CHAR16 *DestPath, + OUT VOID **Resp + ) +{ + SHELL_STATUS ShellStatus; + + // + // First we copy the file + // + ShellStatus = CopySingleFile (Node->FullName, DestPath, Resp, TRUE, L"mv"); + + // + // Check our result + // + if (ShellStatus == SHELL_SUCCESS) { + // + // The copy was successful. delete the source file. + // + CascadeDelete(Node, TRUE); + Node->Handle = NULL; + } else if (ShellStatus == SHELL_ABORTED) { + return EFI_ABORTED; + } else if (ShellStatus == SHELL_ACCESS_DENIED) { + return EFI_ACCESS_DENIED; + } else if (ShellStatus == SHELL_VOLUME_FULL) { + return EFI_VOLUME_FULL; + } else { + return EFI_UNSUPPORTED; + } + + return (EFI_SUCCESS); +} + +/** + Function to take the destination path and target file name to generate the full destination path. + + @param[in] DestPath A pointer to the destination file path string. + @param[out] FullDestPath A pointer to the full destination path string. + @param[in] FileName Name string of the targe file. + + @retval SHELL_SUCCESS the files were all moved. + @retval SHELL_INVALID_PARAMETER a parameter was invalid + @retval SHELL_OUT_OF_RESOURCES a memory allocation failed +**/ +EFI_STATUS +CreateFullDestPath( + IN CONST CHAR16 **DestPath, + OUT CHAR16 **FullDestPath, + IN CONST CHAR16 *FileName + ) +{ + UINTN Size; + if (FullDestPath == NULL || FileName == NULL || DestPath == NULL || *DestPath == NULL){ + return (EFI_INVALID_PARAMETER); + } + + Size = StrSize(*DestPath) + StrSize(FileName); + + *FullDestPath = AllocateZeroPool(Size); + if (*FullDestPath == NULL){ + return (EFI_OUT_OF_RESOURCES); + } + + StrCpyS(*FullDestPath, Size / sizeof(CHAR16), *DestPath); + if ((*FullDestPath)[StrLen(*FullDestPath)-1] != L'\\' && FileName[0] != L'\\') { + StrCatS(*FullDestPath, Size / sizeof(CHAR16), L"\\"); + } + StrCatS(*FullDestPath, Size / sizeof(CHAR16), FileName); + + return (EFI_SUCCESS); +} + +/** + Function to do a move within a file system. + + @param[in] Node A pointer to the file to be removed. + @param[in] DestPath A pointer to the destination file path. + @param[out] Resp A pointer to response from question. Pass back on looped calling. + + @retval SHELL_SUCCESS The source file was moved to the destination. + @retval SHELL_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +MoveWithinFileSystems( + IN EFI_SHELL_FILE_INFO *Node, + IN CHAR16 *DestPath, + OUT VOID **Resp + ) +{ + EFI_FILE_INFO *NewFileInfo; + CHAR16 *TempLocation; + UINTN NewSize; + UINTN Length; + EFI_STATUS Status; + + // + // Chop off map info from DestPath + // + if ((TempLocation = StrStr(DestPath, L":")) != NULL) { + CopyMem(DestPath, TempLocation+1, StrSize(TempLocation+1)); + } + + // + // construct the new file info block + // + NewSize = StrSize(DestPath); + NewSize += StrSize(Node->FileName) + SIZE_OF_EFI_FILE_INFO + sizeof(CHAR16); + NewFileInfo = AllocateZeroPool(NewSize); + if (NewFileInfo == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_MEM), gShellLevel2HiiHandle); + Status = EFI_OUT_OF_RESOURCES; + } else { + CopyMem(NewFileInfo, Node->Info, SIZE_OF_EFI_FILE_INFO); + if (DestPath[0] != L'\\') { + StrCpyS(NewFileInfo->FileName, (NewSize - SIZE_OF_EFI_FILE_INFO) / sizeof(CHAR16), L"\\"); + StrCatS(NewFileInfo->FileName, (NewSize - SIZE_OF_EFI_FILE_INFO) / sizeof(CHAR16), DestPath); + } else { + StrCpyS(NewFileInfo->FileName, (NewSize - SIZE_OF_EFI_FILE_INFO) / sizeof(CHAR16), DestPath); + } + Length = StrLen(NewFileInfo->FileName); + if (Length > 0) { + Length--; + } + if (NewFileInfo->FileName[Length] == L'\\') { + if (Node->FileName[0] == L'\\') { + // + // Don't allow for double slashes. Eliminate one of them. + // + NewFileInfo->FileName[Length] = CHAR_NULL; + } + StrCatS(NewFileInfo->FileName, (NewSize - SIZE_OF_EFI_FILE_INFO) / sizeof(CHAR16), Node->FileName); + } + NewFileInfo->Size = SIZE_OF_EFI_FILE_INFO + StrSize(NewFileInfo->FileName); + + // + // Perform the move operation + // + Status = ShellSetFileInfo(Node->Handle, NewFileInfo); + + // + // Free the info object we used... + // + FreePool(NewFileInfo); + } + + return (Status); +} +/** + function to take a list of files to move and a destination location and do + the verification and moving of those files to that location. This function + will report any errors to the user and continue to move the rest of the files. + + @param[in] FileList A LIST_ENTRY* based list of files to move + @param[out] Resp pointer to response from question. Pass back on looped calling + @param[in] DestParameter the originally specified destination location + + @retval SHELL_SUCCESS the files were all moved. + @retval SHELL_INVALID_PARAMETER a parameter was invalid + @retval SHELL_SECURITY_VIOLATION a security violation ocurred + @retval SHELL_WRITE_PROTECTED the destination was write protected + @retval SHELL_OUT_OF_RESOURCES a memory allocation failed +**/ +SHELL_STATUS +ValidateAndMoveFiles( + IN EFI_SHELL_FILE_INFO *FileList, + OUT VOID **Resp, + IN CONST CHAR16 *DestParameter + ) +{ + EFI_STATUS Status; + CHAR16 *HiiOutput; + CHAR16 *HiiResultOk; + CHAR16 *DestPath; + CHAR16 *FullDestPath; + CONST CHAR16 *Cwd; + CHAR16 *FullCwd; + SHELL_STATUS ShellStatus; + EFI_SHELL_FILE_INFO *Node; + VOID *Response; + UINT64 Attr; + CHAR16 *CleanFilePathStr; + + ASSERT(FileList != NULL); + ASSERT(DestParameter != NULL); + + DestPath = NULL; + FullDestPath = NULL; + Cwd = ShellGetCurrentDir(NULL); + Response = *Resp; + Attr = 0; + CleanFilePathStr = NULL; + FullCwd = NULL; + + if (Cwd != NULL) { + FullCwd = AllocateZeroPool(StrSize(Cwd) + sizeof(CHAR16)); + if (FullCwd == NULL) { + return SHELL_OUT_OF_RESOURCES; + } else { + StrCpyS(FullCwd, StrSize(Cwd)/sizeof(CHAR16)+1, Cwd); + StrCatS(FullCwd, StrSize(Cwd)/sizeof(CHAR16)+1, L"\\"); + } + } + + Status = ShellLevel2StripQuotes (DestParameter, &CleanFilePathStr); + if (EFI_ERROR (Status)) { + SHELL_FREE_NON_NULL(FullCwd); + if (Status == EFI_OUT_OF_RESOURCES) { + return SHELL_OUT_OF_RESOURCES; + } else { + return SHELL_INVALID_PARAMETER; + } + } + + ASSERT (CleanFilePathStr != NULL); + + // + // Get and validate the destination location + // + ShellStatus = GetDestinationLocation(CleanFilePathStr, &DestPath, FullCwd, (BOOLEAN)(FileList->Link.ForwardLink == FileList->Link.BackLink), &Attr); + FreePool (CleanFilePathStr); + + if (ShellStatus != SHELL_SUCCESS) { + SHELL_FREE_NON_NULL (FullCwd); + return (ShellStatus); + } + DestPath = PathCleanUpDirectories(DestPath); + if (DestPath == NULL) { + FreePool (FullCwd); + return (SHELL_OUT_OF_RESOURCES); + } + + HiiOutput = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_MV_OUTPUT), NULL); + HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL); + if (HiiOutput == NULL || HiiResultOk == NULL) { + SHELL_FREE_NON_NULL(DestPath); + SHELL_FREE_NON_NULL(HiiOutput); + SHELL_FREE_NON_NULL(HiiResultOk); + SHELL_FREE_NON_NULL(FullCwd); + return (SHELL_OUT_OF_RESOURCES); + } + + // + // Go through the list of files and directories to move... + // + for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link) + ; !IsNull(&FileList->Link, &Node->Link) + ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link) + ){ + if (ShellGetExecutionBreakFlag()) { + break; + } + + // + // These should never be NULL + // + ASSERT(Node->FileName != NULL); + ASSERT(Node->FullName != NULL); + ASSERT(Node->Info != NULL); + + // + // skip the directory traversing stuff... + // + if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) { + continue; + } + + SHELL_FREE_NON_NULL(FullDestPath); + FullDestPath = NULL; + if (ShellIsDirectory(DestPath)==EFI_SUCCESS) { + CreateFullDestPath((CONST CHAR16 **)&DestPath, &FullDestPath, Node->FileName); + } + + // + // Validate that the move is valid + // + if (!IsValidMove(Node->FullName, FullCwd, FullDestPath!=NULL? FullDestPath:DestPath, Node->Info->Attribute, Attr, Node->Status)) { + ShellStatus = SHELL_INVALID_PARAMETER; + continue; + } + + ShellPrintEx(-1, -1, HiiOutput, Node->FullName, FullDestPath!=NULL? FullDestPath:DestPath); + + // + // See if destination exists + // + if (!EFI_ERROR(ShellFileExists(FullDestPath!=NULL? FullDestPath:DestPath))) { + if (Response == NULL) { + ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response); + } + if (Response == NULL) { + return SHELL_ABORTED; + } + switch (*(SHELL_PROMPT_RESPONSE*)Response) { + case ShellPromptResponseNo: + FreePool(Response); + Response = NULL; + continue; + case ShellPromptResponseCancel: + *Resp = Response; + // + // indicate to stop everything + // + SHELL_FREE_NON_NULL(FullCwd); + return (SHELL_ABORTED); + case ShellPromptResponseAll: + *Resp = Response; + break; + case ShellPromptResponseYes: + FreePool(Response); + Response = NULL; + break; + default: + FreePool(Response); + SHELL_FREE_NON_NULL(FullCwd); + return SHELL_ABORTED; + } + Status = ShellDeleteFileByName(FullDestPath!=NULL? FullDestPath:DestPath); + } + + if (IsBetweenFileSystem(Node->FullName, FullCwd, DestPath)) { + while (FullDestPath == NULL && DestPath != NULL && DestPath[0] != CHAR_NULL && DestPath[StrLen(DestPath) - 1] == L'\\') { + DestPath[StrLen(DestPath) - 1] = CHAR_NULL; + } + Status = MoveBetweenFileSystems(Node, FullDestPath!=NULL? FullDestPath:DestPath, &Response); + } else { + Status = MoveWithinFileSystems(Node, DestPath, &Response); + // + // Display error status + // + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, L"mv", Status); + } + } + + // + // Check our result + // + if (EFI_ERROR(Status)) { + ShellStatus = SHELL_INVALID_PARAMETER; + if (Status == EFI_SECURITY_VIOLATION) { + ShellStatus = SHELL_SECURITY_VIOLATION; + } else if (Status == EFI_WRITE_PROTECTED) { + ShellStatus = SHELL_WRITE_PROTECTED; + } else if (Status == EFI_OUT_OF_RESOURCES) { + ShellStatus = SHELL_OUT_OF_RESOURCES; + } else if (Status == EFI_DEVICE_ERROR) { + ShellStatus = SHELL_DEVICE_ERROR; + } else if (Status == EFI_ACCESS_DENIED) { + ShellStatus = SHELL_ACCESS_DENIED; + } + } else { + ShellPrintEx(-1, -1, L"%s", HiiResultOk); + } + + } // main for loop + + SHELL_FREE_NON_NULL(FullDestPath); + SHELL_FREE_NON_NULL(DestPath); + SHELL_FREE_NON_NULL(HiiOutput); + SHELL_FREE_NON_NULL(HiiResultOk); + SHELL_FREE_NON_NULL(FullCwd); + return (ShellStatus); +} + +/** + Function for 'mv' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunMv ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + CHAR16 *Cwd; + UINTN CwdSize; + SHELL_STATUS ShellStatus; + UINTN ParamCount; + UINTN LoopCounter; + EFI_SHELL_FILE_INFO *FileList; + VOID *Response; + + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + ParamCount = 0; + FileList = NULL; + Response = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"mv", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } + + switch (ParamCount = ShellCommandLineGetCount(Package)) { + case 0: + case 1: + // + // we have insufficient parameters + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"mv"); + ShellStatus = SHELL_INVALID_PARAMETER; + break; + case 2: + // + // must have valid CWD for single parameter... + // + if (ShellGetCurrentDir(NULL) == NULL){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"mv"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList); + if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"mv", ShellCommandLineGetRawValue(Package, 1)); + ShellStatus = SHELL_NOT_FOUND; + } else { + // + // ValidateAndMoveFiles will report errors to the screen itself + // + CwdSize = StrSize(ShellGetCurrentDir(NULL)) + sizeof(CHAR16); + Cwd = AllocateZeroPool(CwdSize); + if (Cwd == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellLevel2HiiHandle, L"mv"); + ShellStatus = SHELL_OUT_OF_RESOURCES; + } else { + StrCpyS (Cwd, CwdSize / sizeof (CHAR16), ShellGetCurrentDir (NULL)); + StrCatS (Cwd, CwdSize / sizeof (CHAR16), L"\\"); + ShellStatus = ValidateAndMoveFiles (FileList, &Response, Cwd); + FreePool (Cwd); + } + } + } + + break; + default: + ///@todo make sure this works with error half way through and continues... + for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount ; LoopCounter++) { + if (ShellGetExecutionBreakFlag()) { + break; + } + Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList); + if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"mv", ShellCommandLineGetRawValue(Package, LoopCounter)); + ShellStatus = SHELL_NOT_FOUND; + } else { + // + // ValidateAndMoveFiles will report errors to the screen itself + // Only change ShellStatus if it's sucessful + // + if (ShellStatus == SHELL_SUCCESS) { + ShellStatus = ValidateAndMoveFiles(FileList, &Response, ShellCommandLineGetRawValue(Package, ParamCount)); + } else { + ValidateAndMoveFiles(FileList, &Response, ShellCommandLineGetRawValue(Package, ParamCount)); + } + } + if (FileList != NULL && !IsListEmpty(&FileList->Link)) { + Status = ShellCloseFileMetaArg(&FileList); + if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) { + ShellStatus = SHELL_ACCESS_DENIED; + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, L"mv", ShellCommandLineGetRawValue(Package, 1), ShellStatus|MAX_BIT); + } + } + } + break; + } // switch on parameter count + + if (FileList != NULL) { + ShellCloseFileMetaArg(&FileList); + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + } + + SHELL_FREE_NON_NULL(Response); + + if (ShellGetExecutionBreakFlag()) { + return (SHELL_ABORTED); + } + + return (ShellStatus); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Parse.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Parse.c new file mode 100644 index 00000000..953fd582 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Parse.c @@ -0,0 +1,311 @@ +/** @file + Main file for Parse shell level 2 function. + + (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel2CommandsLib.h" + +/** + Check if data is coming from StdIn output. + + @param[in] None + + @retval TRUE StdIn stream data available to parse + @retval FALSE StdIn stream data is not available to parse. +**/ +BOOLEAN +IsStdInDataAvailable ( + VOID + ) +{ + SHELL_FILE_HANDLE FileHandle; + EFI_STATUS Status; + CHAR16 CharBuffer; + UINTN CharSize; + UINT64 OriginalFilePosition; + + Status = EFI_SUCCESS; + FileHandle = NULL; + OriginalFilePosition = 0; + + if (ShellOpenFileByName (L">i", &FileHandle, EFI_FILE_MODE_READ, 0) == EFI_SUCCESS) { + CharSize = sizeof(CHAR16); + gEfiShellProtocol->GetFilePosition (FileHandle, &OriginalFilePosition); + Status = gEfiShellProtocol->ReadFile (FileHandle, &CharSize, &CharBuffer); + if (EFI_ERROR (Status) || (CharSize != sizeof(CHAR16))) { + return FALSE; + } + gEfiShellProtocol->SetFilePosition(FileHandle, OriginalFilePosition); + } + + if (FileHandle == NULL) { + return FALSE; + } else { + return TRUE; + } +} + +/** + Handle stings for SFO Output with escape character ^ in a string + 1. Quotation marks in the string must be escaped by using a ^ character (i.e. ^"). + 2. The ^ character may be inserted using ^^. + + @param[in] String The Unicode NULL-terminated string. + + @retval NewString The new string handled for SFO. +**/ +EFI_STRING +HandleStringWithEscapeCharForParse ( + IN CHAR16 *String + ) +{ + EFI_STRING NewStr; + EFI_STRING StrWalker; + EFI_STRING ReturnStr; + + if (String == NULL) { + return NULL; + } + + // + // start to parse the input string. + // + NewStr = AllocateZeroPool (StrSize (String)); + if (NewStr == NULL) { + return NULL; + } + ReturnStr = NewStr; + StrWalker = String; + while (*StrWalker != CHAR_NULL) { + if (*StrWalker == L'^' && (*(StrWalker + 1) == L'^' || *(StrWalker + 1) == L'"')) { + *NewStr = *(StrWalker + 1); + StrWalker++; + } else { + *NewStr = *StrWalker; + } + StrWalker++; + NewStr++; + } + + return ReturnStr; +} + + +/** + Do the actual parsing of the file. the file should be SFO output from a + shell command or a similar format. + + @param[in] FileName The filename to open. + @param[in] TableName The name of the table to find. + @param[in] ColumnIndex The column number to get. + @param[in] TableNameInstance Which instance of the table to get (row). + @param[in] ShellCommandInstance Which instance of the command to get. + @param[in] StreamingUnicode Indicates Input file is StdIn Unicode streaming data or not + + @retval SHELL_NOT_FOUND The requested instance was not found. + @retval SHELL_SUCCESS The operation was successful. +**/ +SHELL_STATUS +PerformParsing( + IN CONST CHAR16 *FileName, + IN CONST CHAR16 *TableName, + IN CONST UINTN ColumnIndex, + IN CONST UINTN TableNameInstance, + IN CONST UINTN ShellCommandInstance, + IN BOOLEAN StreamingUnicode + ) +{ + SHELL_FILE_HANDLE FileHandle; + EFI_STATUS Status; + BOOLEAN Ascii; + UINTN LoopVariable; + UINTN ColumnLoop; + CHAR16 *TempLine; + CHAR16 *ColumnPointer; + SHELL_STATUS ShellStatus; + CHAR16 *TempSpot; + CHAR16 *SfoString; + + ASSERT(FileName != NULL); + ASSERT(TableName != NULL); + + ShellStatus = SHELL_SUCCESS; + + Status = ShellOpenFileByName(FileName, &FileHandle, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellLevel2HiiHandle, L"parse", FileName); + ShellStatus = SHELL_NOT_FOUND; + } else if (!EFI_ERROR (FileHandleIsDirectory (FileHandle))) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_FILE), gShellLevel2HiiHandle, L"parse", FileName); + ShellStatus = SHELL_NOT_FOUND; + } else { + for (LoopVariable = 0 ; LoopVariable < ShellCommandInstance && !ShellFileHandleEof(FileHandle);) { + TempLine = ShellFileHandleReturnLine (FileHandle, &Ascii); + + if ((TempLine == NULL) || (*TempLine == CHAR_NULL && StreamingUnicode)) { + break; + } + + // + // Search for "ShellCommand," in the file to start the SFO table + // for a given ShellCommand. The UEFI Shell spec does not specify + // a space after the comma. + // + if (StrStr (TempLine, L"ShellCommand,") == TempLine) { + LoopVariable++; + } + SHELL_FREE_NON_NULL(TempLine); + } + if (LoopVariable == ShellCommandInstance) { + LoopVariable = 0; + while(1) { + TempLine = ShellFileHandleReturnLine (FileHandle, &Ascii); + if (TempLine == NULL + || *TempLine == CHAR_NULL + || StrStr (TempLine, L"ShellCommand,") == TempLine) { + SHELL_FREE_NON_NULL(TempLine); + break; + } + if (StrStr (TempLine, TableName) == TempLine) { + LoopVariable++; + if (LoopVariable == TableNameInstance + || (TableNameInstance == (UINTN)-1)) { + for (ColumnLoop = 1, ColumnPointer = TempLine; ColumnLoop < ColumnIndex && ColumnPointer != NULL && *ColumnPointer != CHAR_NULL; ColumnLoop++) { + ColumnPointer = StrStr (ColumnPointer, L",\""); + if (ColumnPointer != NULL && *ColumnPointer != CHAR_NULL){ + ColumnPointer++; + } + } + if (ColumnLoop == ColumnIndex) { + if (ColumnPointer == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellLevel2HiiHandle, L"parse", L"Column Index"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + TempSpot = StrStr (ColumnPointer, L",\""); + if (TempSpot != NULL) { + *TempSpot = CHAR_NULL; + } + while (ColumnPointer != NULL && *ColumnPointer != CHAR_NULL && ColumnPointer[0] == L' '){ + ColumnPointer++; + } + if (ColumnPointer != NULL && *ColumnPointer != CHAR_NULL && ColumnPointer[0] == L'\"'){ + ColumnPointer++; + } + if (ColumnPointer != NULL && *ColumnPointer != CHAR_NULL && ColumnPointer[StrLen (ColumnPointer) - 1] == L'\"'){ + ColumnPointer[StrLen (ColumnPointer) - 1] = CHAR_NULL; + } + SfoString = HandleStringWithEscapeCharForParse (ColumnPointer); + if (SfoString != NULL) { + ShellPrintEx (-1, -1, L"%s\r\n", SfoString); + SHELL_FREE_NON_NULL (SfoString); + } + } + } + } + } + SHELL_FREE_NON_NULL(TempLine); + } + } + } + return (ShellStatus); +} + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-i", TypeValue}, + {L"-s", TypeValue}, + {NULL, TypeMax} + }; + +/** + Function for 'parse' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunParse ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + CONST CHAR16 *FileName; + CONST CHAR16 *TableName; + CONST CHAR16 *ColumnString; + SHELL_STATUS ShellStatus; + UINTN ShellCommandInstance; + UINTN TableNameInstance; + BOOLEAN StreamingUnicode; + + ShellStatus = SHELL_SUCCESS; + ProblemParam = NULL; + StreamingUnicode = FALSE; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParseEx (ParamList, &Package, &ProblemParam, TRUE, FALSE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"parse", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + StreamingUnicode = IsStdInDataAvailable (); + if ((!StreamingUnicode && (ShellCommandLineGetCount(Package) < 4)) || + (ShellCommandLineGetCount(Package) < 3)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"parse"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if ((StreamingUnicode && (ShellCommandLineGetCount(Package) > 3)) || + (ShellCommandLineGetCount(Package) > 4)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"parse"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + if (StreamingUnicode) { + FileName = L">i"; + TableName = ShellCommandLineGetRawValue(Package, 1); + ColumnString = ShellCommandLineGetRawValue(Package, 2); + } else { + FileName = ShellCommandLineGetRawValue(Package, 1); + TableName = ShellCommandLineGetRawValue(Package, 2); + ColumnString = ShellCommandLineGetRawValue(Package, 3); + } + if (ShellCommandLineGetValue(Package, L"-i") == NULL) { + TableNameInstance = (UINTN)-1; + } else { + TableNameInstance = ShellStrToUintn(ShellCommandLineGetValue(Package, L"-i")); + } + if (ShellCommandLineGetValue(Package, L"-s") == NULL) { + ShellCommandInstance = 1; + } else { + ShellCommandInstance = ShellStrToUintn(ShellCommandLineGetValue(Package, L"-s")); + } + + ShellStatus = PerformParsing(FileName, TableName, ShellStrToUintn(ColumnString), TableNameInstance, ShellCommandInstance, StreamingUnicode); + } + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + + return (ShellStatus); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Reset.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Reset.c new file mode 100644 index 00000000..752fec37 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Reset.c @@ -0,0 +1,164 @@ +/** @file + Main file for attrib shell level 2 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel2CommandsLib.h" + +STATIC CONST SHELL_PARAM_ITEM ResetParamList[] = { + {L"-w", TypeValue}, + {L"-s", TypeValue}, + {L"-c", TypeValue}, + {L"-fwui", TypeFlag }, + {NULL, TypeMax } + }; + +/** + Function for 'reset' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunReset ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CONST CHAR16 *String; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + UINT64 OsIndications; + UINT32 Attr; + UINTN DataSize; + + ShellStatus = SHELL_SUCCESS; + ProblemParam = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ResetParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"reset", ProblemParam); + FreePool(ProblemParam); + return (SHELL_INVALID_PARAMETER); + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } else if (ShellCommandLineGetRawValue(Package, 1) != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"reset"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + + if (ShellCommandLineGetFlag (Package, L"-fwui")) { + + DataSize = sizeof (OsIndications); + Status = gRT->GetVariable ( + EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME, &gEfiGlobalVariableGuid, + &Attr, &DataSize, &OsIndications + ); + if (!EFI_ERROR (Status)) { + if ((OsIndications & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0) { + DataSize = sizeof (OsIndications); + Status = gRT->GetVariable ( + EFI_OS_INDICATIONS_VARIABLE_NAME, &gEfiGlobalVariableGuid, + &Attr, &DataSize, &OsIndications + ); + if (!EFI_ERROR (Status)) { + OsIndications |= EFI_OS_INDICATIONS_BOOT_TO_FW_UI; + } else { + OsIndications = EFI_OS_INDICATIONS_BOOT_TO_FW_UI; + } + Status = gRT->SetVariable ( + EFI_OS_INDICATIONS_VARIABLE_NAME, &gEfiGlobalVariableGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof (OsIndications), &OsIndications + ); + } + } + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_UNSUPPORTED; + goto Error; + } + } + + // + // check for warm reset flag, then shutdown reset flag, then cold (default) reset flag + // + if (ShellCommandLineGetFlag(Package, L"-w")) { + if (ShellCommandLineGetFlag(Package, L"-s") || ShellCommandLineGetFlag(Package, L"-c")) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"reset"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + String = ShellCommandLineGetValue(Package, L"-w"); + if (String != NULL) { + gRT->ResetSystem(EfiResetWarm, EFI_SUCCESS, StrSize(String), (VOID*)String); + } else { + gRT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL); + } + } + } else if (ShellCommandLineGetFlag(Package, L"-s")) { + if (ShellCommandLineGetFlag(Package, L"-c")) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"reset"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + String = ShellCommandLineGetValue(Package, L"-s"); + DEBUG_CODE(ShellPrintEx(-1,-1,L"Reset with %s (%d bytes)", String, String!=NULL?StrSize(String):0);); + if (String != NULL) { + gRT->ResetSystem(EfiResetShutdown, EFI_SUCCESS, StrSize(String), (VOID*)String); + } else { + gRT->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL); + } + } + } else { + // + // this is default so dont worry about flag... + // + String = ShellCommandLineGetValue(Package, L"-c"); + if (String != NULL) { + gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, StrSize(String), (VOID*)String); + } else { + gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); + } + } + } + } + + // + // we should never get here... so the free and return are for formality more than use + // as the ResetSystem function should not return... + // + +Error: + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + + // + // return the status + // + return (ShellStatus); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Rm.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Rm.c new file mode 100644 index 00000000..40385346 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Rm.c @@ -0,0 +1,374 @@ +/** @file + Main file for attrib shell level 2 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel2CommandsLib.h" + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-q", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Determine if a directory has no files in it. + + @param[in] FileHandle The EFI_HANDLE to the directory. + + @retval TRUE The directory has no files (or directories). + @retval FALSE The directory has at least 1 file or directory in it. +**/ +BOOLEAN +IsDirectoryEmpty ( + IN SHELL_FILE_HANDLE FileHandle + ) +{ + EFI_STATUS Status; + EFI_FILE_INFO *FileInfo; + BOOLEAN NoFile; + BOOLEAN RetVal; + + RetVal = TRUE; + NoFile = FALSE; + FileInfo = NULL; + + for (Status = FileHandleFindFirstFile(FileHandle, &FileInfo) + ; !NoFile && !EFI_ERROR (Status) + ; FileHandleFindNextFile(FileHandle, FileInfo, &NoFile) + ){ + if (StrStr(FileInfo->FileName, L".") != FileInfo->FileName + &&StrStr(FileInfo->FileName, L"..") != FileInfo->FileName) { + RetVal = FALSE; + } + } + return (RetVal); +} + +/** + Delete a node and all nodes under it (including sub directories). + + @param[in] Node The node to start deleting with. + @param[in] Quiet TRUE to print no messages. + + @retval SHELL_SUCCESS The operation was successful. + @retval SHELL_ACCESS_DENIED A file was read only. + @retval SHELL_ABORTED The abort message was received. + @retval SHELL_DEVICE_ERROR A device error occurred reading this Node. +**/ +SHELL_STATUS +CascadeDelete( + IN EFI_SHELL_FILE_INFO *Node, + IN CONST BOOLEAN Quiet + ) +{ + SHELL_STATUS ShellStatus; + EFI_SHELL_FILE_INFO *List; + EFI_SHELL_FILE_INFO *Node2; + EFI_STATUS Status; + SHELL_PROMPT_RESPONSE *Resp; + CHAR16 *TempName; + UINTN NewSize; + + Resp = NULL; + ShellStatus = SHELL_SUCCESS; + List = NULL; + Status = EFI_SUCCESS; + + if ((Node->Info->Attribute & EFI_FILE_READ_ONLY) == EFI_FILE_READ_ONLY) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_RM_LOG_DETELE_RO), gShellLevel2HiiHandle, L"rm", Node->FullName); + return (SHELL_ACCESS_DENIED); + } + + if ((Node->Info->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY) { + if (!IsDirectoryEmpty(Node->Handle)) { + if (!Quiet) { + Status = ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_RM_LOG_DELETE_CONF), gShellLevel2HiiHandle, Node->FullName); + Status = ShellPromptForResponse(ShellPromptResponseTypeYesNo, NULL, (VOID**)&Resp); + ASSERT(Resp != NULL); + if (EFI_ERROR(Status) || *Resp != ShellPromptResponseYes) { + SHELL_FREE_NON_NULL(Resp); + return (SHELL_ABORTED); + } + SHELL_FREE_NON_NULL(Resp); + } + // + // empty out the directory + // + Status = gEfiShellProtocol->FindFilesInDir(Node->Handle, &List); + if (EFI_ERROR(Status)) { + if (List!=NULL) { + gEfiShellProtocol->FreeFileList(&List); + } + return (SHELL_DEVICE_ERROR); + } + for (Node2 = (EFI_SHELL_FILE_INFO *)GetFirstNode(&List->Link) + ; !IsNull(&List->Link, &Node2->Link) + ; Node2 = (EFI_SHELL_FILE_INFO *)GetNextNode(&List->Link, &Node2->Link) + ){ + // + // skip the directory traversing stuff... + // + if (StrCmp(Node2->FileName, L".") == 0 || StrCmp(Node2->FileName, L"..") == 0) { + continue; + } + Node2->Status = gEfiShellProtocol->OpenFileByName (Node2->FullName, &Node2->Handle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE); + if (EFI_ERROR(Node2->Status) && StrStr(Node2->FileName, L":") == NULL) { + // + // Update the node filename to have full path with file system identifier + // + NewSize = StrSize(Node->FullName) + StrSize(Node2->FullName); + TempName = AllocateZeroPool(NewSize); + if (TempName == NULL) { + ShellStatus = SHELL_OUT_OF_RESOURCES; + } else { + StrCpyS(TempName, NewSize/sizeof(CHAR16), Node->FullName); + TempName[StrStr(TempName, L":")+1-TempName] = CHAR_NULL; + StrCatS(TempName, NewSize/sizeof(CHAR16), Node2->FullName); + FreePool((VOID*)Node2->FullName); + Node2->FullName = TempName; + + // + // Now try again to open the file + // + Node2->Status = gEfiShellProtocol->OpenFileByName (Node2->FullName, &Node2->Handle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE); + } + } + if (!EFI_ERROR(Node2->Status)) { + ShellStatus = CascadeDelete(Node2, Quiet); + } else if (ShellStatus == SHELL_SUCCESS) { + ShellStatus = (SHELL_STATUS)(Node2->Status&(~0x80000000)); + } + if (ShellStatus != SHELL_SUCCESS) { + if (List!=NULL) { + gEfiShellProtocol->FreeFileList(&List); + } + return (ShellStatus); + } + } + if (List!=NULL) { + gEfiShellProtocol->FreeFileList(&List); + } + } + } + + if (!(StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0)) { + // + // now delete the current node... + // + if (!Quiet) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_RM_LOG_DELETE), gShellLevel2HiiHandle, Node->FullName); + } + Status = gEfiShellProtocol->DeleteFile(Node->Handle); + Node->Handle = NULL; + } + + // + // We cant allow for the warning here! (Dont use EFI_ERROR Macro). + // + if (Status != EFI_SUCCESS){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_RM_LOG_DELETE_ERR), gShellLevel2HiiHandle, Status); + return (SHELL_ACCESS_DENIED); + } else { + if (!Quiet) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_RM_LOG_DELETE_COMP), gShellLevel2HiiHandle); + } + return (SHELL_SUCCESS); + } +} + +/** + Determines if a Node is a valid delete target. Will prevent deleting the root directory. + + @param[in] List RESERVED. Not used. + @param[in] Node The node to analyze. + @param[in] Package RESERVED. Not used. +**/ +BOOLEAN +IsValidDeleteTarget( + IN CONST EFI_SHELL_FILE_INFO *List, + IN CONST EFI_SHELL_FILE_INFO *Node, + IN CONST LIST_ENTRY *Package + ) +{ + CONST CHAR16 *TempLocation; + BOOLEAN RetVal; + CHAR16 *SearchString; + CHAR16 *Pattern; + UINTN Size; + + if (Node == NULL || Node->FullName == NULL) { + return (FALSE); + } + + TempLocation = StrStr(Node->FullName, L":"); + if (StrLen(TempLocation) <= 2) { + // + // Deleting the root directory is invalid. + // + return (FALSE); + } + + TempLocation = ShellGetCurrentDir(NULL); + if (TempLocation == NULL) { + // + // No working directory is specified so whatever is left is ok. + // + return (TRUE); + } + + Pattern = NULL; + SearchString = NULL; + Size = 0; + Pattern = StrnCatGrow(&Pattern, &Size, TempLocation , 0); + Pattern = StrnCatGrow(&Pattern, &Size, L"\\" , 0); + Size = 0; + SearchString = StrnCatGrow(&SearchString, &Size, Node->FullName, 0); + if (!EFI_ERROR(ShellIsDirectory(SearchString))) { + SearchString = StrnCatGrow(&SearchString, &Size, L"\\", 0); + SearchString = StrnCatGrow(&SearchString, &Size, L"*", 0); + } + + if (Pattern == NULL || SearchString == NULL) { + RetVal = FALSE; + } else { + RetVal = TRUE; + if (gUnicodeCollation->MetaiMatch(gUnicodeCollation, Pattern, SearchString)) { + RetVal = FALSE; + } + } + + SHELL_FREE_NON_NULL(Pattern ); + SHELL_FREE_NON_NULL(SearchString); + + return (RetVal); +} + +/** + Function for 'rm' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunRm ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + CONST CHAR16 *Param; + SHELL_STATUS ShellStatus; + UINTN ParamCount; + EFI_SHELL_FILE_INFO *FileList; + EFI_SHELL_FILE_INFO *Node; + + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + ParamCount = 0; + FileList = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"rm", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } + if (ShellCommandLineGetRawValue(Package, 1) == NULL) { + // + // we insufficient parameters + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"rm"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // get a list with each file specified by parameters + // if parameter is a directory then add all the files below it to the list + // + for ( ParamCount = 1, Param = ShellCommandLineGetRawValue(Package, ParamCount) + ; Param != NULL + ; ParamCount++, Param = ShellCommandLineGetRawValue(Package, ParamCount) + ){ + Status = ShellOpenFileMetaArg((CHAR16*)Param, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList); + if (EFI_ERROR(Status) || FileList == NULL || IsListEmpty(&FileList->Link)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"rm", (CHAR16*)Param); + ShellStatus = SHELL_NOT_FOUND; + break; + } + } + + if (ShellStatus == SHELL_SUCCESS){ + // + // loop through the list and make sure we are not aborting... + // + for ( Node = (EFI_SHELL_FILE_INFO*)GetFirstNode(&FileList->Link) + ; !IsNull(&FileList->Link, &Node->Link) && !ShellGetExecutionBreakFlag() + ; Node = (EFI_SHELL_FILE_INFO*)GetNextNode(&FileList->Link, &Node->Link) + ){ + // + // skip the directory traversing stuff... + // + if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) { + continue; + } + + // + // do the deleting of nodes + // + if (EFI_ERROR(Node->Status)){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_RM_LOG_DELETE_ERR2), gShellLevel2HiiHandle, Node->Status); + ShellStatus = SHELL_ACCESS_DENIED; + break; + } + if (!IsValidDeleteTarget(FileList, Node, Package)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_RM_LOG_DELETE_ERR3), gShellLevel2HiiHandle, Node->FullName); + ShellStatus = SHELL_INVALID_PARAMETER; + break; + } + + ShellStatus = CascadeDelete(Node, ShellCommandLineGetFlag(Package, L"-q")); + } + } + // + // Free the fileList + // + if (FileList != NULL) { + Status = ShellCloseFileMetaArg(&FileList); + } + FileList = NULL; + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + } + + return (ShellStatus); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Set.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Set.c new file mode 100644 index 00000000..6e7de0d7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Set.c @@ -0,0 +1,168 @@ +/** @file + Main file for attrib shell level 2 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel2CommandsLib.h" + +/** + Print out each environment variable registered with the Shell 2.0 GUID. + + If you spawn a pre 2.0 shell from the Shell 2.0 the environment variable may not carry through. + + @retval STATUS_SUCCESS the printout was sucessful + @return any return code from GetNextVariableName except EFI_NOT_FOUND +**/ +SHELL_STATUS +PrintAllShellEnvVars( + VOID + ) +{ + CONST CHAR16 *Value; + CONST CHAR16 *ConstEnvNameList; + + ConstEnvNameList = gEfiShellProtocol->GetEnv(NULL); + if (ConstEnvNameList == NULL) { + return (SHELL_SUCCESS); + } + while (*ConstEnvNameList != CHAR_NULL){ + Value = gEfiShellProtocol->GetEnv(ConstEnvNameList); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SET_DISP), gShellLevel2HiiHandle, ConstEnvNameList, Value); + ConstEnvNameList += StrLen(ConstEnvNameList)+1; + } + + return (SHELL_SUCCESS); +} + +STATIC CONST SHELL_PARAM_ITEM SetParamList[] = { + {L"-d", TypeValue}, + {L"-v", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'set' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunSet ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CONST CHAR16 *KeyName; + CONST CHAR16 *Value; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // Make sure globals are good... + // + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (SetParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"set", ProblemParam); + FreePool(ProblemParam); + return (SHELL_INVALID_PARAMETER); + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } else if (ShellCommandLineGetRawValue(Package, 3) != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"set"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetRawValue(Package, 1) != NULL && ShellCommandLineGetFlag(Package, L"-d")) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"set"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetFlag(Package, L"-d")) { + // + // delete a environment variable + // + KeyName = ShellCommandLineGetValue(Package, L"-d"); + if (KeyName == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellLevel2HiiHandle, L"set", L"-d"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = ShellSetEnvironmentVariable(KeyName, L"", ShellCommandLineGetFlag(Package, L"-v")); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SET_ND), gShellLevel2HiiHandle, L"set", KeyName); + ShellStatus = SHELL_DEVICE_ERROR; + } + } + } else if (ShellCommandLineGetRawValue(Package, 1) == NULL) { + // + // print out all current environment variables + // + return(PrintAllShellEnvVars()); + } else { + // + // we are either printing one or assigning one + // + KeyName = ShellCommandLineGetRawValue(Package, 1); + Value = ShellCommandLineGetRawValue(Package, 2); + if (KeyName != NULL && Value != NULL) { + // + // assigning one + // + Status = ShellSetEnvironmentVariable(KeyName, Value, ShellCommandLineGetFlag(Package, L"-v")); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SET_ERROR_SET), gShellLevel2HiiHandle, L"set", KeyName); + ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT)); + } + + } else { + if (KeyName != NULL) { + // + // print out value for this one only. + // + Value = ShellGetEnvironmentVariable(KeyName); + if (Value == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SET_NF), gShellLevel2HiiHandle, L"set", KeyName); + ShellStatus = SHELL_SUCCESS; + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SET_DISP), gShellLevel2HiiHandle, KeyName, Value); + ShellStatus = SHELL_SUCCESS; + } + } else { + ASSERT(FALSE); + } + } + } + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + + return (ShellStatus); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/TimeDate.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/TimeDate.c new file mode 100644 index 00000000..df76f898 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/TimeDate.c @@ -0,0 +1,966 @@ +/** @file + Main file for time, timezone, and date shell level 2 and shell level 3 functions. + + (C) Copyright 2012-2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel2CommandsLib.h" + +/** + Determine if String is a valid representation for a time or date. + + @param[in] String The pointer to the string to test. + @param[in] Char The delimeter character. + @param[in] Min The minimum value allowed. + @param[in] Max The maximum value allowed. + @param[in] MinusOk Whether negative numbers are permitted. + + @retval TRUE String is a valid representation. + @retval FALSE String is invalid. +**/ +BOOLEAN +InternalIsTimeLikeString ( + IN CONST CHAR16 *String, + IN CONST CHAR16 Char, + IN CONST UINTN Min, + IN CONST UINTN Max, + IN CONST BOOLEAN MinusOk + ) +{ + UINTN Count; + Count = 0; + + if (MinusOk) { + // + // A single minus is ok. + // + if (*String == L'-') { + String++; + } + } + + // + // the first char must be numeric. + // + if (!ShellIsDecimalDigitCharacter(*String)) { + return (FALSE); + } + // + // loop through the characters and use the lib function + // + for ( ; String != NULL && *String != CHAR_NULL ; String++){ + if (*String == Char) { + Count++; + if (Count > Max) { + return (FALSE); + } + continue; + } + if (!ShellIsDecimalDigitCharacter(*String)) { + return (FALSE); + } + } + if (Count < Min) { + return (FALSE); + } + return (TRUE); +} + +/** + Verify that the DateString is valid and if so set that as the current + date. + + @param[in] DateString The pointer to a string representation of the date. + + @retval SHELL_INVALID_PARAMETER DateString was NULL. + @retval SHELL_INVALID_PARAMETER DateString was mis-formatted. + @retval SHELL_SUCCESS The operation was successful. +**/ +SHELL_STATUS +CheckAndSetDate ( + IN CONST CHAR16 *DateString + ) +{ + EFI_TIME TheTime; + EFI_STATUS Status; + CHAR16 *DateStringCopy; + CHAR16 *Walker; + CHAR16 *Walker1; + + if (!InternalIsTimeLikeString(DateString, L'/', 2, 2, FALSE)) { + return (SHELL_INVALID_PARAMETER); + } + + Status = gRT->GetTime(&TheTime, NULL); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"date", L"gRT->GetTime", Status); + return (SHELL_DEVICE_ERROR); + } + + DateStringCopy = NULL; + DateStringCopy = StrnCatGrow(&DateStringCopy, NULL, DateString, 0); + if (DateStringCopy == NULL) { + return (SHELL_OUT_OF_RESOURCES); + } + Walker = DateStringCopy; + + TheTime.Month = 0xFF; + TheTime.Day = 0xFF; + TheTime.Year = 0xFFFF; + + Walker1 = StrStr(Walker, L"/"); + if (Walker1 != NULL && *Walker1 == L'/') { + *Walker1 = CHAR_NULL; + } + + TheTime.Month = (UINT8)ShellStrToUintn (Walker); + if (Walker1 != NULL) { + Walker = Walker1 + 1; + } + Walker1 = Walker!=NULL?StrStr(Walker, L"/"):NULL; + if (Walker1 != NULL && *Walker1 == L'/') { + *Walker1 = CHAR_NULL; + } + if (Walker != NULL && Walker[0] != CHAR_NULL) { + TheTime.Day = (UINT8)ShellStrToUintn (Walker); + if (Walker1 != NULL) { + Walker = Walker1 + 1; + } + Walker1 = Walker!=NULL?StrStr(Walker, L"/"):NULL; + if (Walker1 != NULL && *Walker1 == L'/') { + *Walker1 = CHAR_NULL; + } + if (Walker != NULL && Walker[0] != CHAR_NULL) { + TheTime.Year = (UINT16)ShellStrToUintn (Walker); + } + } + + if (TheTime.Year < 100) { + if (TheTime.Year >= 98) { + TheTime.Year = (UINT16)(1900 + TheTime.Year); + } else { + TheTime.Year = (UINT16)(2000 + TheTime.Year); + } + } + + Status = gRT->SetTime(&TheTime); + + if (!EFI_ERROR(Status)){ + return (SHELL_SUCCESS); + } + return (SHELL_INVALID_PARAMETER); +} + +/** + Function for 'date' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunDate ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + EFI_TIME TheTime; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CONST CHAR16 *Param1; + + ShellStatus = SHELL_SUCCESS; + ProblemParam = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (SfoParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"date", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } else if (ShellCommandLineGetRawValue(Package, 2) != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"date"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // If there are 0 value parameters, then print the current date + // else If there are any value paramerers, then print error + // + if (ShellCommandLineGetRawValue(Package, 1) == NULL) { + // + // get the current date + // + Status = gRT->GetTime(&TheTime, NULL); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"date", L"gRT->GetTime", Status); + return (SHELL_DEVICE_ERROR); + } + + // + // ShellPrintEx the date in SFO or regular format + // + if (ShellCommandLineGetFlag(Package, L"-sfo")) { + // + // Match UEFI Shell spec: + // ShellCommand,"date" + // Date,"DD","MM","YYYY" + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_SFO_HEADER), gShellLevel2HiiHandle, L"date"); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DATE_SFO_FORMAT), gShellLevel2HiiHandle, TheTime.Day, TheTime.Month, TheTime.Year); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_DATE_FORMAT), gShellLevel2HiiHandle, TheTime.Month, TheTime.Day, TheTime.Year); + } + } else { + if (PcdGet8(PcdShellSupportLevel) == 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"date"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // perform level 3 operation here. + // + Param1 = ShellCommandLineGetRawValue(Package, 1); + if (Param1 == NULL) { + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ShellStatus = CheckAndSetDate(Param1); + } + if (ShellStatus != SHELL_SUCCESS) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"date", Param1); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } + } + } + } + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + + // + // return the status + // + return (ShellStatus); +} + +// +// Note "-tz" is invalid for this (non-interactive) version of 'time'. +// +STATIC CONST SHELL_PARAM_ITEM TimeParamList2[] = { + {L"-d", TypeValue}, + {NULL, TypeMax} + }; + +STATIC CONST SHELL_PARAM_ITEM TimeParamList3[] = { + {L"-d", TypeValue}, + {L"-tz", TypeValue}, + {NULL, TypeMax} + }; + +/** + Verify that the TimeString is valid and if so set that as the current + time. + + @param[in] TimeString The pointer to a string representation of the time. + @param[in] Tz The value to set for TimeZone. + @param[in] Daylight The value to set for Daylight. + + @retval SHELL_INVALID_PARAMETER TimeString was NULL. + @retval SHELL_INVALID_PARAMETER TimeString was mis-formatted. + @retval SHELL_SUCCESS The operation was successful. +**/ +SHELL_STATUS +CheckAndSetTime ( + IN CONST CHAR16 *TimeString, + IN CONST INT16 Tz, + IN CONST UINT8 Daylight + ) +{ + EFI_TIME TheTime; + EFI_STATUS Status; + CHAR16 *TimeStringCopy; + CHAR16 *Walker1; + CHAR16 *Walker2; + + if (TimeString != NULL && !InternalIsTimeLikeString(TimeString, L':', 1, 2, FALSE)) { + return (SHELL_INVALID_PARAMETER); + } + if (Daylight != 0xFF &&((Daylight & (EFI_TIME_IN_DAYLIGHT|EFI_TIME_ADJUST_DAYLIGHT)) != Daylight)) { + return (SHELL_INVALID_PARAMETER); + } + + Status = gRT->GetTime(&TheTime, NULL); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"time", L"gRT->GetTime", Status); + return (SHELL_DEVICE_ERROR); + } + + if (TimeString != NULL) { + TimeStringCopy = NULL; + TimeStringCopy = StrnCatGrow(&TimeStringCopy, NULL, TimeString, 0); + Walker1 = TimeStringCopy; + TheTime.Hour = 0xFF; + TheTime.Minute = 0xFF; + + Walker2 = Walker1!=NULL?StrStr(Walker1, L":"):NULL; + if (Walker2 != NULL && *Walker2 == L':') { + *Walker2 = CHAR_NULL; + } + TheTime.Hour = (UINT8)ShellStrToUintn (Walker1); + if (Walker2 != NULL) { + Walker1 = Walker2 + 1; + } + Walker2 = Walker1!=NULL?StrStr(Walker1, L":"):NULL; + if (Walker2 != NULL && *Walker2 == L':') { + *Walker2 = CHAR_NULL; + TheTime.Second = (UINT8)0; + } + else if (Walker2 == NULL) { + TheTime.Second = (UINT8)0; + } + if (Walker1 != NULL && Walker1[0] != CHAR_NULL) { + TheTime.Minute = (UINT8)ShellStrToUintn (Walker1); + if (Walker2 != NULL) { + Walker1 = Walker2 + 1; + if (Walker1 != NULL && Walker1[0] != CHAR_NULL) { + TheTime.Second = (UINT8)ShellStrToUintn (Walker1); + } + } + } + SHELL_FREE_NON_NULL(TimeStringCopy); + } + + + if (Tz >= -1440 && Tz <= 1440) { + // + // EFI_TIME TimeZone is stored to meet the following calculation (see UEFI Spec): + // Localtime = UTC - TimeZone + // This means the sign must be changed for the user provided Tz. + // EX: User wants to set TimeZone to Pacific Standard Time, so runs + // time -tz -480 # set to UTC-08:00 + // To meet the calculation, the sign must be changed. + // + TheTime.TimeZone = -Tz; + } else if (Tz == EFI_UNSPECIFIED_TIMEZONE) { + TheTime.TimeZone = Tz; + } + + if (Daylight != 0xFF) { + TheTime.Daylight = Daylight; + } + + Status = gRT->SetTime(&TheTime); + + if (!EFI_ERROR(Status)){ + return (SHELL_SUCCESS); + } + + return (SHELL_INVALID_PARAMETER); +} + +/** + Function for 'time' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunTime ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + EFI_TIME TheTime; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + INT16 Tz; + UINT8 Daylight; + CONST CHAR16 *TempLocation; + UINTN TzMinutes; + + // + // Initialize variables + // + ShellStatus = SHELL_SUCCESS; + ProblemParam = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + if (PcdGet8(PcdShellSupportLevel) == 2) { + Status = ShellCommandLineParseEx (TimeParamList2, &Package, &ProblemParam, TRUE, TRUE); + } else { + ASSERT(PcdGet8(PcdShellSupportLevel) == 3); + Status = ShellCommandLineParseEx (TimeParamList3, &Package, &ProblemParam, TRUE, TRUE); + } + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"time", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + Status = gRT->GetTime(&TheTime, NULL); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"time", L"gRT->GetTime", Status); + return (SHELL_DEVICE_ERROR); + } + + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } else if (ShellCommandLineGetRawValue(Package, 2) != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"time"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // If there are no parameters, then print the current time + // + if (ShellCommandLineGetRawValue(Package, 1) == NULL + && !ShellCommandLineGetFlag(Package, L"-d") + && !ShellCommandLineGetFlag(Package, L"-tz")) { + // + // ShellPrintEx the current time + // + if (TheTime.TimeZone == EFI_UNSPECIFIED_TIMEZONE) { + TzMinutes = 0; + } else { + TzMinutes = (ABS(TheTime.TimeZone)) % 60; + } + + if (TheTime.TimeZone != EFI_UNSPECIFIED_TIMEZONE) { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_TIME_FORMAT), + gShellLevel2HiiHandle, + TheTime.Hour, + TheTime.Minute, + TheTime.Second, + (TheTime.TimeZone > 0?L"-":L"+"), + ((ABS(TheTime.TimeZone)) / 60), + TzMinutes + ); + } else { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_TIME_FORMAT_LOCAL), + gShellLevel2HiiHandle, + TheTime.Hour, + TheTime.Minute, + TheTime.Second + ); + } + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_CRLF), gShellLevel2HiiHandle); + } else if (ShellCommandLineGetFlag(Package, L"-d") && ShellCommandLineGetValue(Package, L"-d") == NULL) { + if (TheTime.TimeZone == EFI_UNSPECIFIED_TIMEZONE) { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_TIME_FORMAT_LOCAL), + gShellLevel2HiiHandle, + TheTime.Hour, + TheTime.Minute, + TheTime.Second + ); + } else { + TzMinutes = (ABS(TheTime.TimeZone)) % 60; + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_TIME_FORMAT), + gShellLevel2HiiHandle, + TheTime.Hour, + TheTime.Minute, + TheTime.Second, + (TheTime.TimeZone > 0?L"-":L"+"), + ((ABS(TheTime.TimeZone)) / 60), + TzMinutes + ); + } + switch (TheTime.Daylight) { + case 0: + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_TIME_DST0), gShellLevel2HiiHandle); + break; + case EFI_TIME_ADJUST_DAYLIGHT: + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_TIME_DST1), gShellLevel2HiiHandle); + break; + case EFI_TIME_IN_DAYLIGHT: + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_TIME_DST2), gShellLevel2HiiHandle); + break; + case EFI_TIME_IN_DAYLIGHT|EFI_TIME_ADJUST_DAYLIGHT: + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_TIME_DST3), gShellLevel2HiiHandle); + break; + default: + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_ERROR), gShellLevel2HiiHandle, L"time", L"gRT->GetTime", L"TheTime.Daylight", TheTime.Daylight); + } + } else { + if (PcdGet8(PcdShellSupportLevel) == 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"time"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // perform level 3 operation here. + // + if ((TempLocation = ShellCommandLineGetValue(Package, L"-tz")) != NULL) { + if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16 *)TempLocation, L"_local") == 0) { + Tz = EFI_UNSPECIFIED_TIMEZONE; + } else if (TempLocation[0] == L'-') { + + Tz = (INT16) ShellStrToUintn (++TempLocation); + // + // When the argument of "time [-tz tz]" is not numeric, ShellStrToUintn() returns "-1". + // Here we can detect the argument error by checking the return of ShellStrToUintn(). + // + if (Tz == -1) { + Tz = 1441; //make it to be out of bounds value + } else { + Tz *= (-1); //sign convert + } + } else { + if (TempLocation[0] == L'+') { + Tz = (INT16)ShellStrToUintn (++TempLocation); + } else { + Tz = (INT16)ShellStrToUintn (TempLocation); + } + // + // Detect the return of ShellStrToUintn() to make sure the argument is valid. + // + if (Tz == -1) { + Tz = 1441; //make it to be out of bounds value + } + } + if (!(Tz >= -1440 && Tz <= 1440) && Tz != EFI_UNSPECIFIED_TIMEZONE) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellLevel2HiiHandle, L"time", TempLocation, L"-tz"); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } else { + // + // intentionally out of bounds value will prevent changing it... + // + Tz = 1441; + } + TempLocation = ShellCommandLineGetValue(Package, L"-d"); + if (TempLocation != NULL) { + Daylight = (UINT8)ShellStrToUintn(TempLocation); + // + // The argument of "time [-d dl]" is unsigned, if the first character is '-', + // the argument is incorrect. That's because ShellStrToUintn() will skip past + // any '-' sign and convert what's next, forgetting the sign is here. + // + if (TempLocation[0] == '-') { + Daylight = 0xff; //make it invalid = will not use + } + if (Daylight != 0 && Daylight != 1 && Daylight != 3) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellLevel2HiiHandle, L"time", TempLocation, L"-d"); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } else { + // + // invalid = will not use + // + Daylight = 0xFF; + } + if (ShellStatus == SHELL_SUCCESS) { + ShellStatus = CheckAndSetTime(ShellCommandLineGetRawValue(Package, 1), Tz, Daylight); + if (ShellStatus != SHELL_SUCCESS) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"time", ShellCommandLineGetRawValue(Package, 1)); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } + } + } + } + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + + // + // return the status + // + return (ShellStatus); +} + +typedef struct { + INT16 TimeZone; + EFI_STRING_ID StringId; +} TIME_ZONE_ITEM; + +STATIC CONST SHELL_PARAM_ITEM TimeZoneParamList2[] = { + {L"-l", TypeFlag}, + {L"-f", TypeFlag}, + {NULL, TypeMax} + }; +STATIC CONST SHELL_PARAM_ITEM TimeZoneParamList3[] = { + {L"-l", TypeFlag}, + {L"-f", TypeFlag}, + {L"-s", TypeTimeValue}, + {NULL, TypeMax} + }; + + STATIC CONST TIME_ZONE_ITEM TimeZoneList[] = { + {720, STRING_TOKEN (STR_TIMEZONE_M12)}, + {660, STRING_TOKEN (STR_TIMEZONE_M11)}, + {600, STRING_TOKEN (STR_TIMEZONE_M10)}, + {540, STRING_TOKEN (STR_TIMEZONE_M9)}, + {480, STRING_TOKEN (STR_TIMEZONE_M8)}, + {420, STRING_TOKEN (STR_TIMEZONE_M7)}, + {360, STRING_TOKEN (STR_TIMEZONE_M6)}, + {300, STRING_TOKEN (STR_TIMEZONE_M5)}, + {270, STRING_TOKEN (STR_TIMEZONE_M430)}, + {240, STRING_TOKEN (STR_TIMEZONE_M4)}, + {210, STRING_TOKEN (STR_TIMEZONE_M330)}, + {180, STRING_TOKEN (STR_TIMEZONE_M3)}, + {120, STRING_TOKEN (STR_TIMEZONE_M2)}, + {60 , STRING_TOKEN (STR_TIMEZONE_M1)}, + {0 , STRING_TOKEN (STR_TIMEZONE_0)}, + {-60 , STRING_TOKEN (STR_TIMEZONE_P1)}, + {-120 , STRING_TOKEN (STR_TIMEZONE_P2)}, + {-180 , STRING_TOKEN (STR_TIMEZONE_P3)}, + {-210 , STRING_TOKEN (STR_TIMEZONE_P330)}, + {-240 , STRING_TOKEN (STR_TIMEZONE_P4)}, + {-270 , STRING_TOKEN (STR_TIMEZONE_P430)}, + {-300 , STRING_TOKEN (STR_TIMEZONE_P5)}, + {-330 , STRING_TOKEN (STR_TIMEZONE_P530)}, + {-345 , STRING_TOKEN (STR_TIMEZONE_P545)}, + {-360 , STRING_TOKEN (STR_TIMEZONE_P6)}, + {-390 , STRING_TOKEN (STR_TIMEZONE_P630)}, + {-420 , STRING_TOKEN (STR_TIMEZONE_P7)}, + {-480 , STRING_TOKEN (STR_TIMEZONE_P8)}, + {-540 , STRING_TOKEN (STR_TIMEZONE_P9)}, + {-570 , STRING_TOKEN (STR_TIMEZONE_P930)}, + {-600 , STRING_TOKEN (STR_TIMEZONE_P10)}, + {-660 , STRING_TOKEN (STR_TIMEZONE_P11)}, + {-720 , STRING_TOKEN (STR_TIMEZONE_P12)}, + {-780 , STRING_TOKEN (STR_TIMEZONE_P13)}, + {-840 , STRING_TOKEN (STR_TIMEZONE_P14)}, + {EFI_UNSPECIFIED_TIMEZONE, STRING_TOKEN (STR_TIMEZONE_LOCAL)} +}; + +/** + Verify that the TimeZoneString is valid and if so set that as the current + timezone. + + @param[in] TimeZoneString The pointer to a string representation of the timezone. + + @retval SHELL_INVALID_PARAMETER TimeZoneString was NULL. + @retval SHELL_INVALID_PARAMETER TimeZoneString was mis-formatted. + @retval SHELL_SUCCESS The operation was successful. +**/ +SHELL_STATUS +CheckAndSetTimeZone ( + IN CONST CHAR16 *TimeZoneString + ) +{ + EFI_TIME TheTime; + EFI_STATUS Status; + CHAR16 *TimeZoneCopy; + CHAR16 *Walker; + CHAR16 *Walker2; + UINTN LoopVar; + + if (TimeZoneString == NULL) { + return (SHELL_INVALID_PARAMETER); + } + + if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16 *)TimeZoneString, L"_local") == 0) { + Status = gRT->GetTime (&TheTime, NULL); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"gRT->GetTime", Status); + return (SHELL_DEVICE_ERROR); + } + + TheTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE; + Status = gRT->SetTime (&TheTime); + if (!EFI_ERROR(Status)){ + return (SHELL_SUCCESS); + } + return (SHELL_INVALID_PARAMETER); + } + if (TimeZoneString != NULL && !InternalIsTimeLikeString(TimeZoneString, L':', 1, 1, TRUE)) { + return (SHELL_INVALID_PARAMETER); + } + + Status = gRT->GetTime(&TheTime, NULL); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"timezone", L"gRT->GetTime", Status); + return (SHELL_DEVICE_ERROR); + } + + TimeZoneCopy = NULL; + TimeZoneCopy = StrnCatGrow(&TimeZoneCopy, NULL, TimeZoneString, 0); + if (TimeZoneCopy == NULL) { + return (SHELL_OUT_OF_RESOURCES); + } + Walker = TimeZoneCopy; + Walker2 = StrStr(Walker, L":"); + if (Walker2 != NULL && *Walker2 == L':') { + *Walker2 = CHAR_NULL; + } + if (*Walker == L'-') { + TheTime.TimeZone = (INT16)((ShellStrToUintn (++Walker)) * 60); + } else { + TheTime.TimeZone = (INT16)((INT16)(ShellStrToUintn (Walker)) * -60); + } + if (Walker2 != NULL) { + Walker = Walker2 + 1; + } + if (Walker != NULL && Walker[0] != CHAR_NULL) { + if (TheTime.TimeZone < 0) { + TheTime.TimeZone = (INT16)(TheTime.TimeZone - (UINT8)ShellStrToUintn (Walker)); + } else { + TheTime.TimeZone = (INT16)(TheTime.TimeZone + (UINT8)ShellStrToUintn (Walker)); + } + } + + Status = EFI_INVALID_PARAMETER; + + for ( LoopVar = 0 + ; LoopVar < sizeof(TimeZoneList) / sizeof(TimeZoneList[0]) + ; LoopVar++ + ){ + if (TheTime.TimeZone == TimeZoneList[LoopVar].TimeZone) { + Status = gRT->SetTime(&TheTime); + break; + } + } + + FreePool(TimeZoneCopy); + + if (!EFI_ERROR(Status)){ + return (SHELL_SUCCESS); + } + return (SHELL_INVALID_PARAMETER); +} + + +/** + Function for 'timezone' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunTimeZone ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + // + // non interactive + // + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + UINT8 LoopVar; + EFI_TIME TheTime; + BOOLEAN Found; + UINTN TzMinutes; + + ShellStatus = SHELL_SUCCESS; + ProblemParam = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + if (PcdGet8(PcdShellSupportLevel) == 2) { + Status = ShellCommandLineParse (TimeZoneParamList2, &Package, &ProblemParam, TRUE); + } else { + ASSERT(PcdGet8(PcdShellSupportLevel) == 3); + Status = ShellCommandLineParseEx (TimeZoneParamList3, &Package, &ProblemParam, TRUE, TRUE); + } + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"timezone", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetCount(Package) > 1) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"timezone"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } else if (ShellCommandLineGetFlag(Package, L"-s")) { + if ((ShellCommandLineGetFlag(Package, L"-l")) || (ShellCommandLineGetFlag(Package, L"-f"))) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"timezone", L"-l or -f"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(PcdGet8(PcdShellSupportLevel) == 3); + if (ShellCommandLineGetValue(Package, L"-s") == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellLevel2HiiHandle, L"timezone", L"-s"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // Set the time zone + // + ShellStatus = CheckAndSetTimeZone(ShellCommandLineGetValue(Package, L"-s")); + if (ShellStatus != SHELL_SUCCESS) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"timezone", ShellCommandLineGetValue(Package, L"-s")); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } + } + } else if (ShellCommandLineGetFlag(Package, L"-l")) { + // + // Print a list of all time zones + // + for ( LoopVar = 0 + ; LoopVar < sizeof(TimeZoneList) / sizeof(TimeZoneList[0]) + ; LoopVar++ + ){ + ShellPrintHiiEx (-1, -1, NULL, TimeZoneList[LoopVar].StringId, gShellLevel2HiiHandle); + } + } else { + // + // Get Current Time Zone Info + // + Status = gRT->GetTime(&TheTime, NULL); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"timezone", L"gRT->GetTime", Status); + return (SHELL_DEVICE_ERROR); + } + + if (TheTime.TimeZone != EFI_UNSPECIFIED_TIMEZONE) { + Found = FALSE; + for ( LoopVar = 0 + ; LoopVar < sizeof(TimeZoneList) / sizeof(TimeZoneList[0]) + ; LoopVar++ + ){ + if (TheTime.TimeZone == TimeZoneList[LoopVar].TimeZone) { + if (ShellCommandLineGetFlag(Package, L"-f")) { + // + // Print all info about current time zone + // + ShellPrintHiiEx (-1, -1, NULL, TimeZoneList[LoopVar].StringId, gShellLevel2HiiHandle); + } else { + // + // Print basic info only + // + TzMinutes = (ABS(TheTime.TimeZone)) % 60; + + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN(STR_TIMEZONE_SIMPLE), + gShellLevel2HiiHandle, + (TheTime.TimeZone > 0?L"-":L"+"), + (ABS(TheTime.TimeZone)) / 60, + TzMinutes); + } + Found = TRUE; + break; + } + } + if (!Found) { + // + // Print basic info only + // + TzMinutes = (ABS(TheTime.TimeZone)) % 60; + + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN(STR_TIMEZONE_SIMPLE), + gShellLevel2HiiHandle, + (TheTime.TimeZone > 0?L"-":L"+"), + (ABS(TheTime.TimeZone)) / 60, + TzMinutes); + + if (ShellCommandLineGetFlag(Package, L"-f")) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN(STR_TIMEZONE_NI), gShellLevel2HiiHandle); + } + } + } else { + // + // TimeZone was EFI_UNSPECIFIED_TIMEZONE (local) from GetTime() + // + if (ShellCommandLineGetFlag (Package, L"-f")) { + for ( LoopVar = 0 + ; LoopVar < ARRAY_SIZE (TimeZoneList) + ; LoopVar++ + ){ + if (TheTime.TimeZone == TimeZoneList[LoopVar].TimeZone) { + // + // Print all info about current time zone + // + ShellPrintHiiEx (-1, -1, NULL, TimeZoneList[LoopVar].StringId, gShellLevel2HiiHandle); + break; + } + } + } else { + // + // Print basic info only + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_TIMEZONE_SIMPLE_LOCAL), gShellLevel2HiiHandle); + } + } + } + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + + return (ShellStatus); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.c new file mode 100644 index 00000000..9eb9222b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.c @@ -0,0 +1,344 @@ +/** @file + Main file for NULL named library for level 2 shell command functions. + + these functions are: + attrib, + cd, + cp, + date*, + time*, + load, + ls, + map, + mkdir, + mv, + parse, + rm, + reset, + set, + timezone*, + vol + + * functions are non-interactive only + + Copyright (c) 2014 Hewlett-Packard Development Company, L.P. + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "UefiShellLevel2CommandsLib.h" + +CONST CHAR16 mFileName[] = L"ShellCommands"; +EFI_HII_HANDLE gShellLevel2HiiHandle = NULL; + +/** + Get the filename to get help text from if not using HII. + + @retval The filename. +**/ +CONST CHAR16* +EFIAPI +ShellCommandGetManFileNameLevel2 ( + VOID + ) +{ + return (mFileName); +} + +/** + Constructor for the Shell Level 2 Commands library. + + Install the handlers for level 2 UEFI Shell 2.0 commands. + + @param ImageHandle the image handle of the process + @param SystemTable the EFI System Table pointer + + @retval EFI_SUCCESS the shell command handlers were installed sucessfully + @retval EFI_UNSUPPORTED the shell level required was not found. +**/ +EFI_STATUS +EFIAPI +ShellLevel2CommandsLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + // + // if shell level is less than 2 do nothing + // + if (PcdGet8(PcdShellSupportLevel) < 2) { + return (EFI_SUCCESS); + } + + gShellLevel2HiiHandle = HiiAddPackages (&gShellLevel2HiiGuid, gImageHandle, UefiShellLevel2CommandsLibStrings, NULL); + if (gShellLevel2HiiHandle == NULL) { + return (EFI_DEVICE_ERROR); + } + + // + // install our shell command handlers that are always installed + // + ShellCommandRegisterCommandName(L"attrib", ShellCommandRunAttrib , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_ATTRIB) ); + ShellCommandRegisterCommandName(L"cd", ShellCommandRunCd , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_CD) ); + ShellCommandRegisterCommandName(L"cp", ShellCommandRunCp , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_CP) ); + ShellCommandRegisterCommandName(L"load", ShellCommandRunLoad , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_LOAD) ); + ShellCommandRegisterCommandName(L"map", ShellCommandRunMap , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_MAP) ); + ShellCommandRegisterCommandName(L"mkdir", ShellCommandRunMkDir , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_MKDIR) ); + ShellCommandRegisterCommandName(L"mv", ShellCommandRunMv , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_MV) ); + ShellCommandRegisterCommandName(L"parse", ShellCommandRunParse , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_PARSE) ); + ShellCommandRegisterCommandName(L"reset", ShellCommandRunReset , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_RESET) ); + ShellCommandRegisterCommandName(L"set", ShellCommandRunSet , ShellCommandGetManFileNameLevel2, 2, L"",FALSE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_SET) ); + ShellCommandRegisterCommandName(L"ls", ShellCommandRunLs , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_LS) ); + ShellCommandRegisterCommandName(L"rm", ShellCommandRunRm , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_RM) ); + ShellCommandRegisterCommandName(L"vol", ShellCommandRunVol , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_VOL) ); + + // + // support for permanent (built in) aliases + // + ShellCommandRegisterAlias(L"rm", L"del"); + ShellCommandRegisterAlias(L"ls", L"dir"); + ShellCommandRegisterAlias(L"cp", L"copy"); + ShellCommandRegisterAlias(L"mkdir", L"md"); + ShellCommandRegisterAlias(L"cd ..", L"cd.."); + ShellCommandRegisterAlias(L"cd \\", L"cd\\"); + ShellCommandRegisterAlias(L"mv", L"ren"); + ShellCommandRegisterAlias(L"mv", L"move"); + ShellCommandRegisterAlias(L"map", L"mount"); + // + // These are installed in level 2 or 3... + // + if (PcdGet8(PcdShellSupportLevel) == 2 || PcdGet8(PcdShellSupportLevel) == 3) { + ShellCommandRegisterCommandName(L"date", ShellCommandRunDate , ShellCommandGetManFileNameLevel2, PcdGet8(PcdShellSupportLevel), L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_DATE) ); + ShellCommandRegisterCommandName(L"time", ShellCommandRunTime , ShellCommandGetManFileNameLevel2, PcdGet8(PcdShellSupportLevel), L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_TIME) ); + ShellCommandRegisterCommandName(L"timezone", ShellCommandRunTimeZone, ShellCommandGetManFileNameLevel2, PcdGet8(PcdShellSupportLevel), L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_TIMEZONE)); + } else { + DEBUG_CODE_BEGIN(); + // + // we want to be able to test these so install them under a different name in debug mode... + // + ShellCommandRegisterCommandName(L"l2date", ShellCommandRunDate , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_DATE) ); + ShellCommandRegisterCommandName(L"l2time", ShellCommandRunTime , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_TIME) ); + ShellCommandRegisterCommandName(L"l2timezone", ShellCommandRunTimeZone, ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_TIMEZONE)); + DEBUG_CODE_END(); + } + + return (EFI_SUCCESS); +} + +/** + Destructor for the library. free any resources. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. + + @retval EFI_SUCCESS Always returned. +**/ +EFI_STATUS +EFIAPI +ShellLevel2CommandsLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + if (gShellLevel2HiiHandle != NULL) { + HiiRemovePackages(gShellLevel2HiiHandle); + } + return (EFI_SUCCESS); +} + +/** + returns a fully qualified directory (contains a map drive at the begining) + path from a unknown directory path. + + If Path is already fully qualified this will return a duplicat otherwise this + will use get the current directory and use that to build the fully qualified + version. + + if the return value is not NULL it must be caller freed. + + @param[in] Path The unknown Path Value + + @retval NULL A memory allocation failed + @retval NULL A fully qualified path could not be discovered. + @retval other An allocated pointer to a fuly qualified path. +**/ +CHAR16* +GetFullyQualifiedPath( + IN CONST CHAR16* Path + ) +{ + CHAR16 *PathToReturn; + UINTN Size; + CONST CHAR16 *CurDir; + + PathToReturn = NULL; + Size = 0; + + ASSERT((PathToReturn == NULL && Size == 0) || (PathToReturn != NULL)); + // + // convert a local path to an absolute path + // + if (StrStr(Path, L":") == NULL) { + CurDir = gEfiShellProtocol->GetCurDir(NULL); + StrnCatGrow(&PathToReturn, &Size, CurDir, 0); + StrnCatGrow(&PathToReturn, &Size, L"\\", 0); + if (*Path == L'\\') { + Path++; + } + } + StrnCatGrow(&PathToReturn, &Size, Path, 0); + + PathCleanUpDirectories(PathToReturn); + + if (PathToReturn == NULL) { + return NULL; + } + + while (PathToReturn[StrLen(PathToReturn)-1] == L'*') { + PathToReturn[StrLen(PathToReturn)-1] = CHAR_NULL; + } + + return (PathToReturn); +} + +/** + Function to verify all intermediate directories in the path. + + @param[in] Path The pointer to the path to fix. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +VerifyIntermediateDirectories ( + IN CONST CHAR16 *Path + ) +{ + EFI_STATUS Status; + CHAR16 *PathCopy; + CHAR16 *TempSpot; + SHELL_FILE_HANDLE FileHandle; + + ASSERT(Path != NULL); + + Status = EFI_SUCCESS; + PathCopy = NULL; + PathCopy = StrnCatGrow(&PathCopy, NULL, Path, 0); + FileHandle = NULL; + + if (PathCopy == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + for (TempSpot = &PathCopy[StrLen(PathCopy)-1] ; *TempSpot != CHAR_NULL && *TempSpot != L'\\' ; TempSpot = &PathCopy[StrLen(PathCopy)-1]){ + *TempSpot = CHAR_NULL; + } + if (*TempSpot == L'\\') { + *TempSpot = CHAR_NULL; + } + + if (PathCopy != NULL && *PathCopy != CHAR_NULL) { + Status = VerifyIntermediateDirectories(PathCopy); + + if (PathCopy[StrLen(PathCopy)-1] != L':') { + if (!EFI_ERROR(Status)) { + Status = ShellOpenFileByName(PathCopy, &FileHandle, EFI_FILE_MODE_READ, 0); + if (FileHandle != NULL) { + ShellCloseFile(&FileHandle); + } + } + } + } + + SHELL_FREE_NON_NULL(PathCopy); + + return (Status); +} + +/** + String comparison without regard to case for a limited number of characters. + + @param[in] Source The first item to compare. + @param[in] Target The second item to compare. + @param[in] Count How many characters to compare. + + @retval 0 Source and Target are identical strings without regard to case. + @retval !=0 Source is not identical to Target. + +**/ +INTN +StrniCmp( + IN CONST CHAR16 *Source, + IN CONST CHAR16 *Target, + IN CONST UINTN Count + ) +{ + CHAR16 *SourceCopy; + CHAR16 *TargetCopy; + UINTN SourceLength; + UINTN TargetLength; + INTN Result; + + if (Count == 0) { + return 0; + } + + SourceLength = StrLen (Source); + TargetLength = StrLen (Target); + SourceLength = MIN (SourceLength, Count); + TargetLength = MIN (TargetLength, Count); + SourceCopy = AllocateCopyPool ((SourceLength + 1) * sizeof (CHAR16), Source); + if (SourceCopy == NULL) { + return -1; + } + TargetCopy = AllocateCopyPool ((TargetLength + 1) * sizeof (CHAR16), Target); + if (TargetCopy == NULL) { + FreePool (SourceCopy); + return -1; + } + + SourceCopy[SourceLength] = L'\0'; + TargetCopy[TargetLength] = L'\0'; + Result = gUnicodeCollation->StriColl (gUnicodeCollation, SourceCopy, TargetCopy); + FreePool (SourceCopy); + FreePool (TargetCopy); + return Result; +} + + +/** + Cleans off all the quotes in the string. + + @param[in] OriginalString pointer to the string to be cleaned. + @param[out] CleanString The new string with all quotes removed. + Memory allocated in the function and free + by caller. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ShellLevel2StripQuotes ( + IN CONST CHAR16 *OriginalString, + OUT CHAR16 **CleanString + ) +{ + CHAR16 *Walker; + + if (OriginalString == NULL || CleanString == NULL) { + return EFI_INVALID_PARAMETER; + } + + *CleanString = AllocateCopyPool (StrSize (OriginalString), OriginalString); + if (*CleanString == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + for (Walker = *CleanString; Walker != NULL && *Walker != CHAR_NULL ; Walker++) { + if (*Walker == L'\"') { + CopyMem(Walker, Walker+1, StrSize(Walker) - sizeof(Walker[0])); + } + } + + return EFI_SUCCESS; +} + + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.h new file mode 100644 index 00000000..8f6b1cfd --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.h @@ -0,0 +1,363 @@ +/** @file + Main file for NULL named library for level 2 shell command functions. + + these functions are: + attrib, cd, cp, date*, time*, rm, reset, + load, ls, map, mkdir, mv, parse, set, timezone* + + + * functions are non-interactive only + + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _UEFI_SHELL_LEVEL2_COMMANDS_LIB_H_ +#define _UEFI_SHELL_LEVEL2_COMMANDS_LIB_H_ + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern CONST CHAR16 mFileName[]; +extern EFI_HII_HANDLE gShellLevel2HiiHandle; + +/** + Function for 'attrib' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunAttrib ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'date' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunDate ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'time' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunTime ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'load' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunLoad ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'ls' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunLs ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'map' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunMap ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'reset' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunReset ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'timezone' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunTimeZone ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'set' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunSet ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'mkdir' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunMkDir ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'cd' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunCd ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'cp' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunCp ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'parse' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunParse ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'rm' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunRm ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'mv' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunMv ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + returns a fully qualified directory (contains a map drive at the begining) + path from a unknown directory path. + + If Path is already fully qualified this will return a duplicat otherwise this + will use get the current directory and use that to build the fully qualified + version. + + if the return value is not NULL it must be caller freed. + + @param[in] Path The unknown Path Value + + @retval NULL A memory allocation failed + @retval NULL a fully qualified path could not be discovered. + @retval other pointer to a fuly qualified path. +**/ +CHAR16* +GetFullyQualifiedPath( + IN CONST CHAR16* Path + ); + +/** + Function to verify all intermediate directories in the path. + + @param[in] Path The pointer to the path to fix. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +VerifyIntermediateDirectories ( + IN CONST CHAR16 *Path + ); + +/** + String comparison without regard to case for a limited number of characters. + + @param[in] Source The first item to compare. + @param[in] Target The second item to compare. + @param[in] Count How many characters to compare. + + @retval 0 Source and Target are identical strings without regard to case. + @retval !=0 Source is not identical to Target. + +**/ +INTN +StrniCmp( + IN CONST CHAR16 *Source, + IN CONST CHAR16 *Target, + IN CONST UINTN Count + ); + +/** + Cleans off all the quotes in the string. + + @param[in] OriginalString pointer to the string to be cleaned. + @param[out] CleanString The new string with all quotes removed. + Memory allocated in the function and free + by caller. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +ShellLevel2StripQuotes ( + IN CONST CHAR16 *OriginalString, + OUT CHAR16 **CleanString + ); + +/** + Function for 'Vol' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunVol ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function to Copy one file to another location + + If the destination exists the user will be prompted and the result put into *resp + + @param[in] Source pointer to source file name + @param[in] Dest pointer to destination file name + @param[out] Resp pointer to response from question. Pass back on looped calling + @param[in] SilentMode whether to run in quiet mode or not + @param[in] CmdName Source command name requesting single file copy + + @retval SHELL_SUCCESS The source file was copied to the destination +**/ +SHELL_STATUS +CopySingleFile( + IN CONST CHAR16 *Source, + IN CONST CHAR16 *Dest, + OUT VOID **Resp, + IN BOOLEAN SilentMode, + IN CONST CHAR16 *CmdName + ); + +/** + Delete a node and all nodes under it (including sub directories). + + @param[in] Node The node to start deleting with. + @param[in] Quiet TRUE to print no messages. + + @retval SHELL_SUCCESS The operation was successful. + @retval SHELL_ACCESS_DENIED A file was read only. + @retval SHELL_ABORTED The abort message was received. + @retval SHELL_DEVICE_ERROR A device error occurred reading this Node. +**/ +SHELL_STATUS +CascadeDelete( + IN EFI_SHELL_FILE_INFO *Node, + IN CONST BOOLEAN Quiet + ); + +#endif + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf new file mode 100644 index 00000000..d481df56 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf @@ -0,0 +1,79 @@ +## @file +# Provides shell level 2 functions +# +# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiShellLevel2CommandsLib + FILE_GUID = CBF3931C-A2DF-40e5-B77E-CCA9555E9755 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = ShellLevel2CommandsLibConstructor + DESTRUCTOR = ShellLevel2CommandsLibDestructor + +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources.common] + UefiShellLevel2CommandsLib.c + UefiShellLevel2CommandsLib.h + UefiShellLevel2CommandsLib.uni + TimeDate.c + Load.c + Ls.c + Map.c + Reset.c + Set.c + MkDir.c + Cd.c + Cp.c + Parse.c + Rm.c + Mv.c + Attrib.c + Vol.c + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + ShellCommandLib + ShellLib + UefiLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + PcdLib + HiiLib + HandleParsingLib + DevicePathLib + +[Protocols] + gEfiUnicodeCollation2ProtocolGuid ## CONSUMES + gEfiShellProtocolGuid ## CONSUMES + gEfiShellParametersProtocolGuid ## CONSUMES + gEfiDevicePathProtocolGuid ## CONSUMES + gEfiLoadedImageProtocolGuid ## CONSUMES + gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES + +[Pcd.common] + gEfiShellPkgTokenSpaceGuid.PcdShellSupportLevel ## CONSUMES + gEfiShellPkgTokenSpaceGuid.PcdShellFileOperationSize ## CONSUMES + +[Guids] + gEfiFileSystemInfoGuid ## SOMETIMES_CONSUMES ## GUID + gEfiFileInfoGuid ## UNDEFINED + gShellLevel2HiiGuid ## SOMETIMES_CONSUMES ## HII diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.uni b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.uni new file mode 100644 index 00000000..8ce01574 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.uni @@ -0,0 +1,1079 @@ +// /** +// +// (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
+// Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// Module Name: +// +// UefiShellLevel2CommandsLib.uni +// +// Abstract: +// +// String definitions for UEFI Shell 2.0 level 2 commands +// +// +// **/ + +/=# + +#langdef en-US "english" + +#string STR_GEN_NO_MEM #language en-US "%H%s%N: Memory is not available.\r\n" +#string STR_GEN_TOO_MANY #language en-US "%H%s%N: Too many arguments.\r\n" +#string STR_GEN_TOO_FEW #language en-US "%H%s%N: Too few arguments.\r\n" +#string STR_GEN_PARAM_INV #language en-US "%H%s%N: Invalid argument - '%H%s%N'\r\n" +#string STR_GEN_PROBLEM #language en-US "%H%s%N: Unknown flag - '%H%s%N'\r\n" +#string STR_GEN_PROBLEM_VAL #language en-US "%H%s%N: Bad value - '%H%s%N' for flag - '%H%s%N'\r\n" +#string STR_GEN_ATTRIBUTE #language en-US "%H%s%N: Invalid argument - '%H-a%s%N'\r\n" +#string STR_GEN_NO_VALUE #language en-US "%H%s%N: Missing argument for flag - '%H%s%N'\r\n" +#string STR_GEN_ERR_AD #language en-US "%H%s%N: Access denied.\r\n" +#string STR_GEN_ERR_FILE #language en-US "%H%s%N: File '%H%s%N' error - %r\r\n" +#string STR_GEN_ERR_UK #language en-US "%H%s%N: Status: %r\r\n" +#string STR_GEN_PARAM_CON #language en-US "%H%s%N: Parameters conflict.\r\n" +#string STR_GEN_PARAM_CONFLICT #language en-US "%H%s%N: Flags conflict with - '%H%s%N' and '%H%s%N'\r\n" +#string STR_GEN_FILE_OPEN_FAIL #language en-US "%H%s%N: Cannot open file - '%H%s%N'\r\n" +#string STR_GEN_FILE_CLOSE_FAIL #language en-US "%H%s%N: Cannot close file - '%H%s%N'\r\n" +#string STR_GEN_FILE_AD #language en-US "%H%s%N: File access error - '%H%s%N'\r\n" +#string STR_GEN_FILE_NF #language en-US "%H%s%N: File not found - '%H%s%N'\r\n" +#string STR_GEN_CRLF #language en-US "\r\n" +#string STR_GEN_NO_CWD #language en-US "%H%s%N: Current directory not specified.\r\n" +#string STR_GEN_NO_FILES #language en-US "%H%s%N: No matching files were found.\r\n" +#string STR_GEN_DIR_NF #language en-US "%H%s%N: Directory not found - '%H%s%N'\r\n" +#string STR_GEN_RES_OK #language en-US "- [ok]\r\n" +#string STR_GEN_NOT_DIR #language en-US "%H%s%N: '%H%s%N' is not a directory.\r\n" +#string STR_GEN_NOT_FILE #language en-US "%H%s%N: '%H%s%N' is not a file.\r\n" +#string STR_GEN_SFO_HEADER #language en-US "ShellCommand,"%s"\r\n" +#string STR_GEN_MARG_ERROR #language en-US "%H%s%N: The destination '%H%s%N' is ambiguous.\r\n" +#string STR_GEN_FILE_ERROR #language en-US "%H%s%N: The destination is an existing file '%H%s%N'.\r\n" +#string STR_GEN_UEFI_FUNC_ERROR #language en-US "%H%s%N: UEFI function '%H%s%N' returned an incorrect value for: %s (%x).\r\n" +#string STR_GEN_UEFI_FUNC_WARN #language en-US "%H%s%N: UEFI function '%H%s%N' returned: %r\r\n" +#string STR_GEN_DEST_EXIST_OVR #language en-US "Destination file already exists. Overwrite? %BY%Nes, %BN%No, %BA%Nll, %BC%Nancel " +#string STR_GEN_CPY_FAIL #language en-US "%H%s%N: Copy failure: insufficient capacity on destination media.\r\n" +#string STR_GEN_CPY_READ_ERROR #language en-US "%H%s%N: reading '%B%s%N': IO Error \r\n" +#string STR_GEN_CPY_WRITE_ERROR #language en-US "%H%s%N: writing '%B%s%N': IO Error \r\n" +#string STR_GEN_OUT_MEM #language en-US "%H%s%N: Memory allocation was not successful.\r\n" + +#string STR_SET_DISP #language en-US "%V%8s %N= %H%s%N\r\n" +#string STR_SET_NF #language en-US "%H%s%N: Environment Variable '%H%s%N' not defined.\r\n" +#string STR_SET_ND #language en-US "%H%s%N: Environment Variable '%H%s%N' could not be deleted.\r\n" +#string STR_SET_ERROR_SET #language en-US "%H%s%N: Unable to set %H%s%N\r\n" + +#string STR_CD_PRINT #language en-US "%s\r\n" +#string STR_CD_NF #language en-US "%H%s%N: No mapping found.\r\n" + +#string STR_MAP_NF #language en-US "%H%s%N: Cannot find mapped device - '%H%s%N'\r\n" +#string STR_MAP_NOF #language en-US "%H%s%N: No mappable target found - '%H%s%N'\r\n" +#string STR_MAP_SFO_MAPPINGS #language en-US "Mappings,"%s","%s","%s"\r\n" +#string STR_MAP_HEADER #language en-US "%EMapping table%N\r\n" +#string STR_MAP_ENTRY #language en-US "%E%10s%N %HAlias(s):%N%s\r\n %s\r\n" +#string STR_MAP_ENTRY_VERBOSE #language en-US " Handle: [%H%02x%N]\r\n" + " Media Type: %s\r\n" + " Removable: %s\r\n" + " Current Dir: %s\r\n" + +#string STR_ATTRIB_OUTPUT_LINE #language en-US "Attrib: %1c%1c%1c%1c%1c %s\r\n" + +#string STR_MAP_MEDIA_FLOPPY #language en-US "Floppy" +#string STR_MAP_MEDIA_UNKNOWN #language en-US "Unknown" +#string STR_MAP_MEDIA_HARDDISK #language en-US "HardDisk" +#string STR_MAP_MEDIA_CDROM #language en-US "CD-Rom" + +#string STR_MKDIR_ALREADY #language en-US "Directory '%B%s%N' already exists.\r\n" +#string STR_MKDIR_CREATEFAIL #language en-US "Directory '%B%s%N' unable to create.\r\n" + +#string STR_DATE_FORMAT #language en-US "%02d/%02d/%04d\r\n" +#string STR_DATE_SFO_FORMAT #language en-US "Date,"%02d","%02d","%04d"\r\n" + +#string STR_TIME_FORMAT #language en-US "%02d:%02d:%02d (UTC%1s%02d:%02d)" +#string STR_TIME_FORMAT_LOCAL #language en-US "%02d:%02d:%02d (LOCAL)" +#string STR_TIME_DST0 #language en-US " DST: Not Affected\r\n" +#string STR_TIME_DST1 #language en-US " DST: Affected\r\n" +#string STR_TIME_DST2 #language en-US " DST: Adjusted\r\n" +#string STR_TIME_DST3 #language en-US " DST: Affected and Adjusted\r\n" + +#string STR_TIMEZONE_M12 #language en-US "UTC-12:00, International Date Line West\r\n" +#string STR_TIMEZONE_M11 #language en-US "UTC-11:00, Midway Island, Samoa\r\n" +#string STR_TIMEZONE_M10 #language en-US "UTC-10:00, Hawaii\r\n" +#string STR_TIMEZONE_M9 #language en-US "UTC-09:00, Alaska\r\n" +#string STR_TIMEZONE_M8 #language en-US "UTC-08:00, Pacific Time(US & Canada), Tijuana, Portland\r\n" +#string STR_TIMEZONE_M7 #language en-US "UTC-07:00, Arizona, Chihuahua, La Paz, Mazatlan, Mountain Time (US & Canada)\r\n" +#string STR_TIMEZONE_M6 #language en-US "UTC-06:00, Central America, Central Time(US & Canada)\r\n" +#string STR_TIMEZONE_M5 #language en-US "UTC-05:00, Bogota, Lima, Quito, Eastern Time(US & Canada)\r\n" +#string STR_TIMEZONE_M430 #language en-US "UTC-04:30, Caracas\r\n" +#string STR_TIMEZONE_M4 #language en-US "UTC-04:00, Atlantic Time(Canada), Caracas, Santiago, Georgetown\r\n" +#string STR_TIMEZONE_M330 #language en-US "UTC-03:30, Newfoundland\r\n" +#string STR_TIMEZONE_M3 #language en-US "UTC-03:00, Brasilia, Buenos Aires, Greenland\r\n" +#string STR_TIMEZONE_M2 #language en-US "UTC-02:00, Mid-Atlantic\r\n" +#string STR_TIMEZONE_M1 #language en-US "UTC-01:00, Azores, Cape Verde Is.\r\n" +#string STR_TIMEZONE_0 #language en-US "UTC , Greenwich Mean Time, Casablanca, Monrovia, Dublin, London\r\n" +#string STR_TIMEZONE_P1 #language en-US "UTC+01:00, Amsterdam, Berlin, Bern, Rome, Paris, West Central Africa\r\n" +#string STR_TIMEZONE_P2 #language en-US "UTC+02:00, Athens, Bucharest, Cairo, Jerusalem\r\n" +#string STR_TIMEZONE_P3 #language en-US "UTC+03:00, Baghdad, Kuwait, Riyadh, Moscow, Nairobi, Istanbul\r\n" +#string STR_TIMEZONE_P330 #language en-US "UTC+03:30, Tehran\r\n" +#string STR_TIMEZONE_P4 #language en-US "UTC+04:00, Abu Dhabi, Muscat, Baku, Tbilisi, Yerevan\r\n" +#string STR_TIMEZONE_P430 #language en-US "UTC+04:30, Kabul\r\n" +#string STR_TIMEZONE_P5 #language en-US "UTC+05:00, Ekaterinburg, Islamabad, Karachi, Tashkent\r\n" +#string STR_TIMEZONE_P530 #language en-US "UTC+05:30, Chennai, Kolkata, Mumbai, New Delhi\r\n" +#string STR_TIMEZONE_P545 #language en-US "UTC+05:45, Kathmandu\r\n" +#string STR_TIMEZONE_P6 #language en-US "UTC+06:00, Almaty, Astana, Dhaka, Sri Jayawardenepura\r\n" +#string STR_TIMEZONE_P630 #language en-US "UTC+06:30, Rangoon\r\n" +#string STR_TIMEZONE_P7 #language en-US "UTC+07:00, Bangkok, Hanio, Jakarta, Krasnoyarsk, Novosibirsk\r\n" +#string STR_TIMEZONE_P8 #language en-US "UTC+08:00, Beijing, Chongqing, Hong Kong, Urumqi, Taipei, Perth\r\n" +#string STR_TIMEZONE_P9 #language en-US "UTC+09:00, Osaka, Sapporo, Tokyo, Seoul, Yakutsk\r\n" +#string STR_TIMEZONE_P930 #language en-US "UTC+09:30, Adelaide, Darwin\r\n" +#string STR_TIMEZONE_P10 #language en-US "UTC+10:00, Canberra, Melbourne, Sydney, Guam, Hobart, Vladivostok\r\n" +#string STR_TIMEZONE_P11 #language en-US "UTC+11:00, Magadan, Solomon Is., New Caledonia\r\n" +#string STR_TIMEZONE_P12 #language en-US "UTC+12:00, Auckland, Wellington, Fiji, Kamchatka, Marshall Is.\r\n" +#string STR_TIMEZONE_P13 #language en-US "UTC+13:00, Nuku'alofa\r\n" +#string STR_TIMEZONE_P14 #language en-US "UTC+14:00, Line Islands\r\n" +#string STR_TIMEZONE_LOCAL #language en-US "LOCAL , Local Time\r\n" +#string STR_TIMEZONE_SIMPLE #language en-US "UTC%1s%02d:%02d\r\n" +#string STR_TIMEZONE_SIMPLE_LOCAL #language en-US "LOCAL\r\n" +#string STR_TIMEZONE_NI #language en-US "No additional information known." + +#string STR_LOAD_NOT_IMAGE #language en-US "Image '%s' is not an image.\r\n" +#string STR_LOAD_NOT_DRIVER #language en-US "Image '%s' is not a driver.\r\n" +#string STR_LOAD_LOADED #language en-US "Image '%s' loaded at %x - %r\r\n" +#string STR_LOAD_ERROR #language en-US "Image '%s' error in StartImage: %r\r\n" + +#string STR_LS_LINE_START_ALL #language en-US "%t %5s %1c % ,L11d " +#string STR_LS_LINE_END_FILE #language en-US "%s\r\n" +#string STR_LS_LINE_END_EXE #language en-US "%V%s%N\r\n" +#string STR_LS_LINE_END_DIR #language en-US "%B%s%N\r\n" +#string STR_LS_FOOTER_LINE #language en-US "% ,L11d File(s) % ,L11d bytes\r\n% ,L11d Dir(s)\r\n" +#string STR_LS_HEADER_LINE1 #language en-US "Directory of: %H%s%N\r\n" +#string STR_LS_FILE_NOT_FOUND #language en-US "%H%s%N: File Not Found - '%H%s%N'\r\n" +#string STR_LS_SFO_VOLINFO #language en-US "VolumeInfo,"%s","%Ld","%5s","%Ld","%Ld"\r\n" +#string STR_LS_SFO_FILEINFO #language en-US "FileInfo,"%s","%Ld","%Ld","%s%s%s%s%s","%02d:%02d:%02d","%02d.%02d.%04d","%02d:%02d:%02d","%02d.%02d.%04d","%02d:%02d:%02d","%02d.%02d.%04d"\r\n" + +#string STR_VOL_VOLINFO #language en-US "Volume %s (%s)\r\n" + "%Ld bytes total disk space\r\n" + "%Ld bytes available on disk\r\n" + "%d bytes in each allocation unit\r\n" + +#string STR_RM_LOG_DELETE_CONF #language en-US "Remove Subtree '%B%s%N' [y/n]?" +#string STR_RM_LOG_DELETE #language en-US "Deleting '%B%s%N'\r\n" +#string STR_RM_LOG_DELETE_ERR #language en-US "Delete error: %r\r\n" +#string STR_RM_LOG_DELETE_ERR2 #language en-US "Delete error. Couldn't open file: %r\r\n" +#string STR_RM_LOG_DELETE_ERR3 #language en-US "Delete error. Invalid target '%B%s%N'\r\n" +#string STR_RM_LOG_DELETE_COMP #language en-US "Delete successful.\r\n" +#string STR_RM_LOG_DETELE_RO #language en-US "%H%s%N: '%H%s%N' is read-only\r\n" + +#string STR_MV_OUTPUT #language en-US "Moving %s -> %s\r\n" +#string STR_MV_INV_SUB #language en-US "Cannot move a directory into itself or its subdirectory.\r\n" +#string STR_MV_INV_RO #language en-US "Cannot move to or from a read-only file or directory '%B%s%N'\r\n" +#string STR_MV_INV_CWD #language en-US "Cannot move current working directory or its subdirectory.\r\n" + +#string STR_CP_OUTPUT #language en-US "Copying %s -> %s\r\n" +#string STR_CP_ERROR #language en-US "%H%s%N: Could not copy - '%H%s%N'\r\n" +#string STR_CP_DIR_REQ #language en-US "%H%s%N: Copying a directory requires -r.\r\n" +#string STR_CP_DIR_WNF #language en-US "%H%s%N: The specified path does not exist - '%H%s%N'\r\n" +#string STR_CP_SD_SAME #language en-US "%H%s%N: The source and destination are the same.\r\n" +#string STR_CP_SD_PARENT #language en-US "%H%s%N: The destination is a parent of the source.\r\n" +#string STR_CP_DEST_ERROR #language en-US "%H%s%N: The destination is read-only.\r\n" +#string STR_CP_DEST_OPEN_FAIL #language en-US "%H%s%N: The destination file '%B%s%N' failed to open with create.\r\n" +#string STR_CP_DEST_DIR_FAIL #language en-US "%H%s%N: The destination directory '%B%s%N' could not be created.\r\n" +#string STR_CP_SRC_OPEN_FAIL #language en-US "%H%s%N: The source file '%B%s%N' failed to open with read.\r\n" + +#string STR_GET_HELP_ATTRIB #language en-US "" +".TH attrib 0 "Displays or modifies the attributes of files or directories."\r\n" +".SH NAME\r\n" +"Displays or modifies the attributes of files or directories.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"ATTRIB [+a|-a] [+s|-s] [+h|-h] [+r|-r] [file...] [directory...]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" +a|-a - Sets or clears the 'archive' attribute.\r\n" +" +s|-s - Sets or clears the 'system' attribute.\r\n" +" +h|-h - Sets or clears the 'hidden' attribute.\r\n" +" +r|-r - Sets or clears the 'read-only' attribute.\r\n" +" file - Specifies the file name (wild cards are permitted).\r\n" +" directory - Specifies the directory name (wildcards are permitted).\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. Four attribute types are supported in the UEFI file system:\r\n" +" - Archive [A]\r\n" +" - System [S]\r\n" +" - Hidden [H]\r\n" +" - Read only [R]\r\n" +" 2. If a file (in general meaning) is a directory, then it is also shown\r\n" +" to have the attribute [D].\r\n" +" 3. If any file in the file list that is specified \r\n" +" does not exist, attrib will continue processing the remaining files\r\n" +" while reporting the error.\r\n" +" 4. If no attributes parameters are specified, the current attributes of\r\n" +" the specified files or directories are displayed.\r\n" +" 5. If no files or directories are specified, the command applies to\r\n" +" all files and sub-directories within the current directory.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display the attributes of a directory:\r\n" +" fs0:\> attrib fs0:\ \r\n" +" \r\n" +" * To display the attributes of all files and sub-directories in the current\r\n" +" directory:\r\n" +" fs0:\> attrib *\r\n" +" \r\n" +" * To add the system attribute to all files with extension '.efi':\r\n" +" fs0:\> attrib +s *.efi\r\n" +" \r\n" +" * To remove the read-only attribute from all files with extension '.inf':\r\n" +" fs0:\> attrib -r *.inf\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_NOT_FOUND The requested file was not found.\r\n" +" SHELL_INVALID_PARAMETER One of the passed-in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_WRITE_PROTECTED The media that the action was to take place on is\r\n" +" write-protected.\r\n" + +#string STR_GET_HELP_CD #language en-US "" +".TH cd 0 "Displays or changes the current directory."\r\n" +".SH NAME\r\n" +"Displays or changes the current directory.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"CD [path]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" path - Specifies the relative or absolute directory path.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command changes the current working directory that is used by the\r\n" +" UEFI Shell environment. If a file system mapping is specified, then the\r\n" +" current working directory is changed for that device. Otherwise, the\r\n" +" current working directory is changed for the current device.\r\n" +" 2. If path is not present, then the current working directory (including\r\n" +" file system mapping) is displayed to standard out.\r\n" +" 3. The table below describes the conventions that are used to refer to the\r\n" +" directory, its parent, and the root directory in the UEFI Shell\r\n" +" environment.\r\n" +" Convention Description\r\n" +" '.' Refers to the current directory.\r\n" +" '..' Refers to the directory's parent.\r\n" +" '\\\' Refers to the root of the current file system.\r\n" +" 4. The current working directory is maintained in the environment\r\n" +" variable %cwd%.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To change the current file system to the mapped fs0 file system:\r\n" +" Shell> fs0:\r\n" +" \r\n" +" * To change the current directory to subdirectory 'efi':\r\n" +" fs0:\> cd efi\r\n" +" \r\n" +" * To change the current directory to the parent directory (fs0:\):\r\n" +" fs0:\efi\> cd ..\r\n" +" \r\n" +" * To change the current directory to 'fs0:\efi\Tools':\r\n" +" fs0:\> cd efi\Tools\r\n" +" \r\n" +" * To change the current directory to the root of the current fs (fs0):\r\n" +" fs0:\efi\Tools\> cd \ \r\n" +" \r\n" +" * To move between volumes and maintain the current path, and then copy\r\n" +" all of files in fs0:\efi\Tools into the fs1:\Tmp directory:\r\n" +" fs0:\> cd \efi\Tools\r\n" +" fs0:\efi\Tools\> fs1:\r\n" +" fs1:\> cd Tmp\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_INVALID_PARAMETER One of the passed-in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" + +#string STR_GET_HELP_CP #language en-US "" +".TH cp 0 "Copies files or directories."\r\n" +".SH NAME\r\n" +"Copies one or more files or directories to another location.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"CP [-r] [-q] src [src...] [dst]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -r - Makes a recursive copy.\r\n" +" -q - Makes a quiet copy (without a prompt).\r\n" +" src - Specifies a source file/directory name (wildcards are permitted).\r\n" +" dst - Specifies a destination file/directory name (wildcards are not permitted). \r\n" +" If more than one directory is specified, the last directory is\r\n" +" assumed to be the destination.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. '-r' must be specified if src is a directory. If '-r' is specified,\r\n" +" the source directory is recursively copied to the destination.\r\n" +" 'src' itself is copied.\r\n" +" 2. If a destination is not specified, the current working directory is\r\n" +" assumed to be the destination.\r\n" +" 3. 'CP -r src1 src2 dst' copies all files and subdirectories in 'src1' and\r\n" +" 'src2' to the destination 'dst'. 'src1' and 'src2' themselves are also\r\n" +" copied. The 'dst' parameter is interpreted as a directory.\r\n" +" 4. Copying a directory or file to itself is not allowed.\r\n" +" 5. If an error occurs, this command exits immediately and the remaining files or\r\n" +" directories are not copied.\r\n" +" 6. When 'cp' is executed with a script file, it always performs quiet\r\n" +" copying, regardless of whether the '-q' option is specified.\r\n" +" 7. If you are copying multiple files, the destination must be an existing\r\n" +" directory.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display the contents of the current directory:\r\n" +" fs0:\> ls\r\n" +" \r\n" +" * To copy a file in the same directory and change the file name:\r\n" +" fs0:\> cp temp.txt readme.txt\r\n" +" \r\n" +" * To copy multiple files to another directory:\r\n" +" fs0:\> cp temp.txt isaBus.efi \Test\r\n" +" \r\n" +" * To copy multiple directories recursively to another directory:\r\n" +" fs0:\> cp -r test1 test2 boot \Test\r\n" +" \r\n" +" * To see the results of the above operations:\r\n" +" fs0:\> ls \Test\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_INVALID_PARAMETER One of the passed-in parameters was incorrectly \r\n" +" formatted or its value was out of bounds.\r\n" +" SHELL_OUT_OF_RESOURCES There was insufficient space to save the \r\n" +" requested file at the destination.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security \r\n" +" violation.\r\n" +" SHELL_WRITE_PROTECTED An attempt was made to create a file on media that\r\n" +" was write-protected.\r\n" + +#string STR_GET_HELP_MAP #language en-US "" +".TH map 0 "Displays or defines file system mappings"\r\n" +".SH NAME\r\n" +"Displays or defines file system mappings.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"MAP [-d ]\r\n" +"MAP [[-r][-v][-c][-f][-u][-t ][sname]]\r\n" +"MAP [sname handle | mapping]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -d - Deletes a file system mapping.\r\n" +" -r - Resets file system mappings to default values.\r\n" +" -u - Adds file system mappings for newly-installed devices and\r\n" +" removes mappings for uninstalled devices. This does not change\r\n" +" the mappings of existing devices and preserves user-defined mappings.\r\n" +" -v - Displays verbose information about all file system mappings.\r\n" +" -c - Displays the consistent mappings.\r\n" +" -f - Displays the normal mappings (not the consistent mappings).\r\n" +" -t - Displays the device mappings, filtered according to the device type.\r\n" +" Supported types are:\r\n" +" fp - Floppy\r\n" +" hd - Hard Disk\r\n" +" cd - CD-ROM\r\n" +" Types can be combined by putting a comma between two types. Spaces\r\n" +" are not allowed between types.\r\n" +" -sfo - Displays information in Standard-Format Output.\r\n" +" sname - Specifies a mapping name.\r\n" +" handle - Specifies the number of a handle. Use the same value that is\r\n" +" displayed by the 'dh' command.\r\n" +" mapping - Specifies a new mapping name to assign to a device.\r\n" +" This value must end with a ':'.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command creates a mapping between a user-defined name and a device.\r\n" +" The most common use of this command is to create a mapped name for\r\n" +" devices that support a file system protocol. After these mappings are\r\n" +" created, the names can be used with all the file manipulation commands.\r\n" +" 2. The UEFI Shell environment creates default mappings for all of the\r\n" +" devices that support a recognized file system.\r\n" +" 3. This command can be used to create additional mappings, or \r\n" +" when used with the -d option, to delete an existing mapping. If it is\r\n" +" used without any parameters, all of the current mappings are listed.\r\n" +" If the -v option is used, the mappings are shown with additional\r\n" +" information about each device.\r\n" +" 4. The -r option is used to reset all the default mappings in a system,\r\n" +" which is useful if the system configuration has changed since the\r\n" +" last boot.\r\n" +" 5. The -u option adds mappings for newly-installed devices and removes\r\n" +" mappings for uninstalled devices without changing the mappings of\r\n" +" existing devices. User-defined mappings are also preserved. A mapping\r\n" +" history is saved, which preserves the original mapping name for\r\n" +" a device with a specific device path. The current directory is also\r\n" +" preserved if the current device is not changed.\r\n" +" 6. Each device in the system has a consistent mapping. If the hardware\r\n" +" configuration has not changed, the device's consistent mappings do not\r\n" +" change. If two or more machines have the same hardware configurations,\r\n" +" the device's consistent mapping remains the same. Use the -c option to\r\n" +" list all the consistent mappings in the system.\r\n" +" 7. The mapping value must consist of digits and characters. Other\r\n" +" characters are illegal.\r\n" +" 8. This command support wildcards. You can use the wildcards to delete\r\n" +" or show the mapping. However, when you assign the mapping, wildcards\r\n" +" are forbidden.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display verbose mapping table information:\r\n" +" Shell> map -v\r\n" +" \r\n" +" * To assign a different name to fs0:\r\n" +" Shell> map floppy fs0:\r\n" +" \r\n" +" * To operate with the mapped name:\r\n" +" Shell> floppy:\r\n" +" \r\n" +" * To delete a mapped name:\r\n" +" Shell> map -d floppy:\r\n" +" \r\n" +" * To display all the mapped names starting with 'f': \r\n" +" Shell> map f* \r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_INVALID_PARAMETER One of the passed-in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" + +#string STR_GET_HELP_MKDIR #language en-US "" +".TH mkdir 0 "Creates directories."\r\n" +".SH NAME\r\n" +"Creates one or more new directories.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"MKDIR dir [dir...]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" dir - Specifies the name of a directory or directories to create.\r\n" +" (Wildcards are not allowed)\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. Mkdir can create one or more new directories.\r\n" +" 2. If dir includes nested directories, then parent directories will be\r\n" +" created before child directories.\r\n" +" 3. If the directory already exists, mkdir will exit with an error.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To create a new directory:\r\n" +" fs0:\> mkdir rafter\r\n" +" \r\n" +" * To create multiple directories:\r\n" +" fs0:\> mkdir temp1 temp2\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_INVALID_PARAMETER One of the passed-in parameters was incorrectly \r\n" +" formatted or its value was out of bounds.\r\n" +" SHELL_OUT_OF_RESOURCES There was insufficient space on the destination \r\n" +" to create the requested directory.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security \r\n" +" violation.\r\n" +" SHELL_WRITE_PROTECTED An attempt was made to create a directory when the\r\n" +" target media was write-protected.\r\n" + +#string STR_GET_HELP_MV #language en-US "" +".TH mv 0 "Moves files."\r\n" +".SH NAME\r\n" +"Moves one or more files to a destination within or between file systems.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"MV src [src...] [dst]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" src - Specifies a source file/directory name (wildcards are permitted).\r\n" +" dst - Specifies a destination file/directory name (wildcards are permitted).\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command moves one or more files to a destination within or between\r\n" +" file systems.\r\n" +" 2. If the destination is an existing directory, the sources are moved\r\n" +" into that directory. You cannot move the sources to a non-existing\r\n" +" directory.\r\n" +" 3. If a destination is not specified, the current directory is assumed to be\r\n" +" the destination. If there is more than one argument on the command line,\r\n" +" the last one is assumed to be the destination.\r\n" +" 4. Attempting to move a read-only file/directory results in an error.\r\n" +" Moving a directory that contains read-only files is allowed.\r\n" +" 5. You cannot move a directory into itself or its subdirectories.\r\n" +" 6. You cannot move a directory if the current working directory is itself or\r\n" +" its subdirectories.\r\n" +" 7. If an error occurs, the remaining files or directories are still be\r\n" +" moved.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To rename a file:\r\n" +" fs0:\> mv IsaBus.efi Bus.efi\r\n" +" \r\n" +" * To move a directory to the current directory:\r\n" +" fs0:\> mkdir Test1\Temp\r\n" +" fs0:\> mv Test1\Temp\r\n" +" \r\n" +" * To rename a directory:\r\n" +" fs0:\> mv efi efi1.1\r\n" +" \r\n" +" * To move multiple directories at a time:\r\n" +" fs0:\> mv Test1 Test2 Test\r\n" +" \r\n" +" * To attempt moving a read-only directory, which results in a failure:\r\n" +" fs0:\Test> attrib +r Temp1\r\n" +" DA R fs0:\Test\Temp1\r\n" +" fs0:\Test> mv Temp1 Temp2\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_INVALID_PARAMETER One of the passed-in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" +" SHELL_NOT_FOUND The source file was not able to be found.\r\n" +" SHELL_OUT_OF_RESOURCES There was insufficient free space to move the\r\n" +" requested file to its destination.\r\n" +" SHELL_WRITE_PROTECTED An attempt was made to create a file on media that\r\n" +" was write-protected.\r\n" + +#string STR_GET_HELP_PARSE #language en-US "" +".TH parse 0 "Parses standard format output files."\r\n" +".SH NAME\r\n" +"Retrieves a value from a standard format output file.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"PARSE filename tablename column [-i ] [-s ]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" filename - Specifies a source file name.\r\n" +" tablename - Specifies the name of the table to be parsed.\r\n" +" column - Specifies the one-based column index to use to determine which value\r\n" +" from a particular record to parse.\r\n" +" -i - Specifies an instance number to use to start parsing the ShellCommand table,\r\n" +" and then the specified tablename. If not specified, all instances are returned.\r\n" +" -s - Specifies an instance number to use to start parsing the ShellCommand\r\n" +" table. If not present, then 1 is assumed.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command enables you to parse data from a file that has been output\r\n" +" using the -sfo parameter.\r\n" +" 2. Since the standard formatted output has a well known means of parsing,\r\n" +" this command is intended to provide an easy way of enabling\r\n" +" scripts to consume retrieved data from such constructed output files, and\r\n" +" use it in the logic of scripts written for the UEFI shell.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * The following data is contained in a temporary file (temp.txt):\r\n" +" ShellCommand,"ls"\r\n" +" VolumeInfo,"MikesVolume","400000000","FALSE","32000000","16000000"\r\n" +" FileInfo,"FS0:\efi\\boot\winloader.efi","45670","45900","arsh","08:30:12","01.08.2013","00:00:00","01.08.2013","08:30:12","01.08.2013"\r\n" +" FileInfo,"FS0:\efi\\boot\mikesfile.txt","1250","1280","a","08:30:12","01.08.2013","00:00:00","01.08.2013","08:30:12","01.08.2013"\r\n" +" FileInfo,"FS0:\efi\\boot\\readme.txt","795","900","a","08:30:12","01.08.2013","00:00:00","01.08.2013","08:30:12","01.08.2013"\r\n" +" \r\n" +" * To display VolumeInfo column 2 in temp.txt:\r\n" +" fs0:\> parse temp.txt VolumeInfo 2\r\n" +" MikesVolume\r\n" +" \r\n" +" * To display FileInfo column 3 in temp.txt, starting with instance 3:\r\n" +" fs0:\> parse temp.txt FileInfo 3 -i 3\r\n" +" 795\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_INVALID_PARAMETER One of the passed-in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" +" SHELL_NOT_FOUND The source file was not able to be found.\r\n" + +#string STR_GET_HELP_RESET #language en-US "" +".TH reset 0 "Reset the system."\r\n" +".SH NAME\r\n" +"Resets the system.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"RESET [-w [string]]\r\n" +"RESET [-s [string]]\r\n" +"RESET [-c [string]]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -s - Performs a shutdown.\r\n" +" -w - Performs a warm boot.\r\n" +" -c - Performs a cold boot.\r\n" +" string - Describes a reason for the reset.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command resets the system.\r\n" +" 2. The default is to perform a cold reset unless the -w parameter is\r\n" +" specified.\r\n" +" 3. If a reset string is specified, it is passed into the Reset() \r\n" +" function, and the system records the reason for the system reset.\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_INVALID_PARAMETER One of the passed in parameters was incorrectly \r\n" +" formatted or its value was out of bounds.\r\n" + +#string STR_GET_HELP_RM #language en-US "" +".TH rm 0 "Deletes one or more files or directories."\r\n" +".SH NAME\r\n" +"Deletes one or more files or directories.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"RM [-q] file/directory [file/directory ...]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -q - Specifies quiet mode. Does not prompt for a confirmation.\r\n" +" file - Specifies a file name (wildcards are permitted).\r\n" +" directory - Specifies a directory name (wildcards are permitted).\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command deletes one or more files or directories.\r\n" +" 2. If the target is a directory, it deletes the directory, including all\r\n" +" its subdirectories.\r\n" +" 3. Redirecting a file whose parent directory (or the file\r\n" +" itself) is being deleted is not allowed.\r\n" +" 4. Removing a read-only file/directory results in a failure.\r\n" +" 5. Removing a directory containing read-only file(s) results in\r\n" +" a failure. If an error occurs, the command exits immediately and stops\r\n" +" removing files/directories.\r\n" +" 6. You cannot remove a directory when the current directory is itself or its\r\n" +" subdirectory. If a file contains wildcards, you are not prompted for\r\n" +" confirmation.\r\n" +" 7. The root directory cannot be removed.\r\n" +" 8. The current directory or its ancestor directories cannot be removed.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To remove multiple directories at a time:\r\n" +" fs0:\> rm Test\Temp1 Temp2\r\n" +" \r\n" +" * To remove multiple directories with wildcards:\r\n" +" fs0:\> rm Test\Temp*\r\n" +" \r\n" +" * To attempt removing a directory that contains a read-only file,\r\n" +" which results in a failure:\r\n" +" fs0:\> attrib +r Test\Temp1\readme.txt\r\n" +" A R fs0:\Test\Temp1\readme.txt\r\n" +" fs0:\> rm Test\Temp1\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_NOT_FOUND The source file was not able to be found.\r\n" +" SHELL_WRITE_PROTECTED The target was write protected.\r\n" + +#string STR_GET_HELP_SET #language en-US "" +".TH set 0 "Displays or modifies UEFI Shell environment variables."\r\n" +".SH NAME\r\n" +"Displays or modifies UEFI Shell environment variables.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"SET [-v] [sname [value]]\r\n" +"SET [-d ]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -d - Deletes the environment variable.\r\n" +" -v - Displays or modifies a volatile variable.\r\n" +" sname - Specifies an environment variable name.\r\n" +" value - Specifies an environment variable value.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command is used to maintain the UEFI Shell environment variables.\r\n" +" This command can do the following:\r\n" +" - Display environment variables.\r\n" +" - Create new environment variables.\r\n" +" - Change the value of existing environment variables.\r\n" +" - Delete environment variables.\r\n" +" 2. This command sets an environment variable to a specified \r\n" +" value. You can use it to create a new environment\r\n" +" variable or to modify an existing environment variable.\r\n" +" 3. If used without any parameters, all the environment variables\r\n" +" are displayed.\r\n" +" 4. If used with the -d option, the environment variable that\r\n" +" is specified by sname is deleted.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To add an environment variable:\r\n" +" Shell> set DiagnosticPath fs0:\efi\diag;fs1:\efi\diag\r\n" +" \r\n" +" * To display environment variables:\r\n" +" Shell> set\r\n" +" \r\n" +" * To delete an environment variable:\r\n" +" Shell> set -d diagnosticpath\r\n" +" \r\n" +" * To change an environment variable:\r\n" +" fs0:\> set src efi\r\n" +" fs0:\> set src efi1.1\r\n" +" \r\n" +" * To append an environment variable:\r\n" +" Shell> set path %path%;fs0:\efi\Tools;fs0:\efi\boot;fs0:\\r\n" +" \r\n" +" * To set a volatile variable that will disappear at the next boot:\r\n" +" Shell> set -v EFI_SOURCE c:\project\EFI1.1\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_OUT_OF_RESOURCES A request to set a variable in a non-volatile \r\n" +" fashion could not be completed. The resulting \r\n" +" non-volatile request has been converted into a \r\n" +" volatile request.\r\n" + +#string STR_GET_HELP_DATE #language en-US "" +".TH date 0 "Displays and sets the current date for the system."\r\n" +".SH NAME\r\n" +"Displays and sets the current date for the system.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"DATE [mm/dd/[yy]yy][-sfo]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -sfo - Displays information in Standard-Format Output.\r\n" +" mm - Specifies the month of the date to be set. (1-12)\r\n" +" dd - Specifies the day of the date to be set (1-31)\r\n" +" yy/yyyy - Specifies the year of the date to be set. If only two digits,\r\n" +" then enter 9x = 199x. Otherwise enter 20xx.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command displays and/or sets the current date for the system.\r\n" +" If no parameters are used, it shows the current date. If a valid month,\r\n" +" day, and year are specified, the system's date is updated.\r\n" +" The following rules apply:\r\n" +" - Except for numeric characters and /, all other characters in the\r\n" +" argument are invalid.\r\n" +" - The Shell reports an error if the number is in the wrong\r\n" +" month/date/year range.\r\n" +" - A space before or after the numeric character is not allowed. Inserting\r\n" +" a space into the number is invalid.\r\n" +" - Repeated zeros are allowed before the number. For example:\r\n" +" Shell > date 0000008/000004/000097\r\n" +" Shell > date\r\n" +" 08/04/2097\r\n" +" Shell >\r\n" +" - The year range must be greater than or equal to 1998.\r\n" +" - Two numeric characters indicate the year. Numbers below 98 are\r\n" +" regarded as 20xx, and numbers equal to or above 98 are regarded as\r\n" +" 19xx. 00 means 2000. For example:\r\n" +" Shell > date 8/4/97\r\n" +" Shell > date\r\n" +" 08/04/2097\r\n" +" Shell >\r\n" +" Shell > date 8/4/98\r\n" +" Shell > date\r\n" +" 08/04/1998\r\n" +" Shell >\r\n" +" 2. The range of valid years is from 1998-2099.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display the current date in the system:\r\n" +" fs0:\> date\r\n" +" \r\n" +" * To set the date with long year format:\r\n" +" fs0:\> date 01/01/2050\r\n" +" \r\n" +" * To set the date with short year format:\r\n" +" fs0:\> date 06/18/01\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_DEVICE_ERROR There was a hardware error preventing the\r\n" +" completion of this command.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_INVALID_PARAMETER One of the passed-in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" + +#string STR_GET_HELP_TIME #language en-US "" +".TH time 0 "Displays or sets the time for the system."\r\n" +".SH NAME\r\n" +"Displays or sets the current time for the system.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"TIME [hh:mm[:ss]] [-tz tz] [-d dl]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -d - Sets or displays a daylight savings time value.\r\n" +" -tz - Specifies a time zone adjustment, measured in minutes offset from UTC. Valid values\r\n" +" are between -1440 and 1440 or 2047. If not present or set to 2047,\r\n" +" time is interpreted as local time.\r\n" +" hh - Specifies a new hour (0-23) (required).\r\n" +" mm - Specifies a new minute (0-59) (required).\r\n" +" ss - Specifies a new second (0-59). If not specified, zero is used.\r\n" +" dl - Specifies a daylight saving time value to set.\r\n" +" 0 : Time is not affected.\r\n" +" 1 : Time is affected, and has not been adjusted for daylight\r\n" +" savings.\r\n" +" 3 : Time is affected, and has been adjusted for daylight savings.\r\n" +" All other values are invalid. If no value follows -d, the\r\n" +" current daylight savings time is displayed.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command displays or sets the current time for the system.\r\n" +" If no parameters are used, it shows the current time. If valid hours, \r\n" +" minutes, and seconds are provided, the system time is\r\n" +" updated. Note the following rules:\r\n" +" - Except for numeric characters and the : character, all other\r\n" +" characters in the argument are invalid.\r\n" +" - The Shell reports an error if the number is in the wrong \r\n" +" hour/minute/second range.\r\n" +" - Spaces before or after the numeric character and spaces inserted into\r\n" +" the number are not allowed.\r\n" +" - Repeated zeros are allowed before the number. For example:\r\n" +" Shell> time 00000017:000004:0000\r\n" +" Shell> time\r\n" +" 17:04:00 (UTC+08:00)\r\n" +" 2. The seconds parameter is optional. If none is specified, it is\r\n" +" set to zero.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display current system time:\r\n" +" fs0:\> time\r\n" +" \r\n" +" * To set the system time:\r\n" +" fs0:\> time 9:51:30\r\n" +" \r\n" +" * To display the system time, including daylight savings time:\r\n" +" fs0:\> time -d\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_DEVICE_ERROR There was a hardware error preventing the\r\n" +" completion of this command\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_INVALID_PARAMETER One of the passed-in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" + +#string STR_GET_HELP_TIMEZONE #language en-US "" +".TH timezone 0 "Displays or sets time zone information."\r\n" +".SH NAME\r\n" +"Displays or sets time zone information.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"TIMEZONE [-s hh:mm | -l] [-b] [-f]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -s - Sets the time zone associated with hh:mm offset from UTC.\r\n" +" -l - Displays a list of all time zones.\r\n" +" -b - Displays one screen at a time.\r\n" +" -f - Displays full information for the specified time zone.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command displays and sets the current time zone for the system.\r\n" +" 2. If no parameters are used, it shows the current time zone.\r\n" +" 3. If a valid hh:mm parameter is provided, the time zone\r\n" +" information is updated.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display all available time zones:\r\n" +" Shell> timezone -l\r\n" +" \r\n" +" * To set the time zone:\r\n" +" Shell> timezone -s -7:00\r\n" +" \r\n" +" * To display detailed information for the current time zone:\r\n" +" Shell> timezone -f\r\n" + +#string STR_GET_HELP_LS #language en-US "" +".TH ls 0 "Lists the contents of a directory or file information."\r\n" +".SH NAME\r\n" +"Lists the contents of a directory or file information.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"LS [-r] [-a[attrib]][-sfo][file]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -r - Displays recursively (including subdirectories).\r\n" +" -a - Displays files with a specified attribute. If \r\n" +" attribute is not specified, all files are listed. If -a is not\r\n" +" specified, all non-system and non-hidden files are listed.\r\n" +" -sfo - Displays information in Standard-Format Output.\r\n" +" attrib - Specifies a file attribute list value:\r\n" +" a - Archive\r\n" +" s - System\r\n" +" h - Hidden\r\n" +" r - Read-only\r\n" +" d - Directory\r\n" +" file - Specifies a name of a file or directory (wildcards are permitted).\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command lists directory contents or file information. If no file\r\n" +" name or directory name is specified, the current working directory\r\n" +" is assumed.\r\n" +" 2. The contents of a directory are listed if all of the following are true:\r\n" +" - If option -r is not specified.\r\n" +" - If no wildcard characters are specified in the file parameter.\r\n" +" - If the file specified represents an existing directory.\r\n" +" 3. In all other cases, the command functions as follows:\r\n" +" - All files/directories that match the specified name are displayed.\r\n" +" - The -r flag determines whether a recursive search is performed.\r\n" +" - The option flag -a[attrib] only displays those\r\n" +" files with the attributes that are specified.\r\n" +" - If more than one attribute is specified, only the files that have all\r\n" +" those attributes are listed.\r\n" +" - If -a is followed by nothing, then all files/directories are\r\n" +" displayed, regardless of their attributes.\r\n" +" - If -a itself is not specified, then all files except system and\r\n" +" hidden files are displayed.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To hide files by adding the hidden or system attribute to them:\r\n" +" fs0:\> attrib +s +h *.efi\r\n" +" \r\n" +" * To display all, except the files/directories with 'h' or 's' attribute:\r\n" +" fs0:\> ls\r\n" +" \r\n" +" * To display files with all attributes in the current directory:\r\n" +" fs0:\> ls -a\r\n" +" \r\n" +" * To display files with read-only attributes in the current directory:\r\n" +" fs0:\> ls -ar\r\n" +" \r\n" +" * To display the files with attribute of 's':\r\n" +" fs0:\> ls -as isabus.efi\r\n" +" \r\n" +" * To display all in fs0:\efi directory recursively:\r\n" +" fs0:\> ls -r -a efi\r\n" +" \r\n" +" * To display files with a specified type in the current directory: \r\n" +" recursively:\r\n" +" fs0:\> ls -r -a *.efi -b\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_INVALID_PARAMETER One of the passed-in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_NOT_FOUND The requested file or directory was not found.\r\n" + +#string STR_GET_HELP_LOAD #language en-US "" +".TH load 0 "Loads a UEFI driver into memory."\r\n" +".SH NAME\r\n" +"Loads a UEFI driver into memory.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"LOAD [-nc] file [file...]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -nc - Loads the driver, but does not connect the driver.\r\n" +" File - Specifies a file that contains the image of the UEFI driver (wildcards are\r\n" +" permitted).\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command loads a driver into memory. It can load multiple files at\r\n" +" one time. The file name supports wildcards.\r\n" +" 2. If the -nc flag is not specified, this command attempts to connect the\r\n" +" driver to a proper device. It might also cause previously loaded drivers\r\n" +" to be connected to their corresponding devices.\r\n" +" 3. Use the 'UNLOAD' command to unload a driver.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To load a driver:\r\n" +" fs0:\> load Isabus.efi\r\n" +" \r\n" +" * To load multiple drivers:\r\n" +" fs0:\> load Isabus.efi IsaSerial.efi\r\n" +" \r\n" +" * To load multiple drivers using file name wildcards:\r\n" +" fs0:\> load Isa*.efi\r\n" +" \r\n" +" * To load a driver without connecting it to a device:\r\n" +" fs0:\> load -nc IsaBus.efi\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_INVALID_PARAMETER One of the passed-in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_NOT_FOUND The requested file was not found.\r\n" + +#string STR_GET_HELP_VOL #language en-US "" +".TH vol 0 "Displays or modifies information about a disk volume."\r\n" +".SH NAME\r\n" +"Displays or modifies information about a disk volume.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"VOL [fs] [-n ]\r\n" +"VOL [fs] [-d]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -n - Displays or modifies a new volume label.\r\n" +" -d - Displays or modifies an empty volume label.\r\n" +" fs - Specifies the name of the file system.\r\n" +" VolumeLabel - Specifies a volume label.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. The following characters cannot be used in a volume label:\r\n" +" % ^ * + = [ ] | : ; \" < > ? / . \r\n" +" 2. No spaces are allowed in a volume label.\r\n" +" 3. This command displays the volume information for the specified file\r\n" +" system. If fs is not specified, the current file system is used.\r\n" +" 4. If -n is specified, the volume label for fs is set to\r\n" +" VolumeLabel.\r\n" +" 5. The maximum length for volume label is 11 characters.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display the volume of the current file system:\r\n" +" fs0:\> vol\r\n" +" \r\n" +" * To change the label of fs0:\r\n" +" Shell> vol fs0 -n help_test\r\n" +" \r\n" +" * To delete the volume label of fs0:\r\n" +" fs0:\> vol fs0 -d\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_INVALID_PARAMETER One of the passed-in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_NOT_FOUND The target file-system was not found.\r\n" + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Vol.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Vol.c new file mode 100644 index 00000000..0666732b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel2CommandsLib/Vol.c @@ -0,0 +1,307 @@ +/** @file + Main file for vol shell level 2 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel2CommandsLib.h" +#include +#include + +/** + Print the info or change the volume info. + + @param[in] Path String with starting path. + @param[in] Delete TRUE to delete the volume label. FALSE otherwise. + @param[in] Name New name to set to the volume label. + + @retval SHELL_SUCCESS The operation was sucessful. +**/ +SHELL_STATUS +HandleVol( + IN CONST CHAR16 *Path, + IN CONST BOOLEAN Delete, + IN CONST CHAR16 *Name OPTIONAL + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + EFI_FILE_SYSTEM_INFO *SysInfo; + UINTN SysInfoSize; + SHELL_FILE_HANDLE ShellFileHandle; + EFI_FILE_PROTOCOL *EfiFpHandle; + UINTN Size1; + UINTN Size2; + + ShellStatus = SHELL_SUCCESS; + + if ( + Name != NULL && ( + StrStr(Name, L"%") != NULL || + StrStr(Name, L"^") != NULL || + StrStr(Name, L"*") != NULL || + StrStr(Name, L"+") != NULL || + StrStr(Name, L"=") != NULL || + StrStr(Name, L"[") != NULL || + StrStr(Name, L"]") != NULL || + StrStr(Name, L"|") != NULL || + StrStr(Name, L":") != NULL || + StrStr(Name, L";") != NULL || + StrStr(Name, L"\"") != NULL || + StrStr(Name, L"<") != NULL || + StrStr(Name, L">") != NULL || + StrStr(Name, L"?") != NULL || + StrStr(Name, L"/") != NULL || + StrStr(Name, L" ") != NULL ) + ){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"vol", Name); + return (SHELL_INVALID_PARAMETER); + } + + Status = gEfiShellProtocol->OpenFileByName( + Path, + &ShellFileHandle, + Name != NULL?EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE:EFI_FILE_MODE_READ); + + if (EFI_ERROR(Status) || ShellFileHandle == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellLevel2HiiHandle, L"vol", Path); + return (SHELL_ACCESS_DENIED); + } + + // + // Get the Volume Info from ShellFileHandle + // + SysInfo = NULL; + SysInfoSize = 0; + EfiFpHandle = ConvertShellHandleToEfiFileProtocol(ShellFileHandle); + Status = EfiFpHandle->GetInfo( + EfiFpHandle, + &gEfiFileSystemInfoGuid, + &SysInfoSize, + SysInfo); + + if (Status == EFI_BUFFER_TOO_SMALL) { + SysInfo = AllocateZeroPool(SysInfoSize); + Status = EfiFpHandle->GetInfo( + EfiFpHandle, + &gEfiFileSystemInfoGuid, + &SysInfoSize, + SysInfo); + } + + ASSERT(SysInfo != NULL); + + if (Delete) { + *((CHAR16 *) SysInfo->VolumeLabel) = CHAR_NULL; + SysInfo->Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize(SysInfo->VolumeLabel); + Status = EfiFpHandle->SetInfo( + EfiFpHandle, + &gEfiFileSystemInfoGuid, + (UINTN)SysInfo->Size, + SysInfo); + } else if (Name != NULL) { + Size1 = StrSize(Name); + Size2 = StrSize(SysInfo->VolumeLabel); + if (Size1 > Size2) { + SysInfo = ReallocatePool((UINTN)SysInfo->Size, (UINTN)SysInfo->Size + Size1 - Size2, SysInfo); + if (SysInfo == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellLevel2HiiHandle, L"vol"); + ShellStatus = SHELL_OUT_OF_RESOURCES; + } + } + if (SysInfo != NULL) { + StrCpyS ( (CHAR16 *) SysInfo->VolumeLabel, + (Size1>Size2? Size1/sizeof(CHAR16) : Size2/sizeof(CHAR16)), + Name + ); + SysInfo->Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + Size1; + Status = EfiFpHandle->SetInfo( + EfiFpHandle, + &gEfiFileSystemInfoGuid, + (UINTN)SysInfo->Size, + SysInfo); + } + } + + FreePool(SysInfo); + + if (Delete || Name != NULL) { + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_AD), gShellLevel2HiiHandle, L"vol", Path); + ShellStatus = SHELL_ACCESS_DENIED; + } + } + + SysInfoSize = 0; + SysInfo = NULL; + + Status = EfiFpHandle->GetInfo( + EfiFpHandle, + &gEfiFileSystemInfoGuid, + &SysInfoSize, + SysInfo); + + if (Status == EFI_BUFFER_TOO_SMALL) { + SysInfo = AllocateZeroPool(SysInfoSize); + Status = EfiFpHandle->GetInfo( + EfiFpHandle, + &gEfiFileSystemInfoGuid, + &SysInfoSize, + SysInfo); + } + + gEfiShellProtocol->CloseFile(ShellFileHandle); + + ASSERT(SysInfo != NULL); + + if (SysInfo != NULL) { + // + // print VolumeInfo table + // + ShellPrintHiiEx ( + 0, + gST->ConOut->Mode->CursorRow, + NULL, + STRING_TOKEN (STR_VOL_VOLINFO), + gShellLevel2HiiHandle, + SysInfo->VolumeLabel, + SysInfo->ReadOnly?L"r":L"rw", + SysInfo->VolumeSize, + SysInfo->FreeSpace, + SysInfo->BlockSize + ); + SHELL_FREE_NON_NULL(SysInfo); + } + + return (ShellStatus); +} + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-d", TypeFlag}, + {L"-n", TypeValue}, + {NULL, TypeMax} + }; + +/** + Function for 'Vol' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunVol ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CONST CHAR16 *PathName; + CONST CHAR16 *CurDir; + BOOLEAN DeleteMode; + CHAR16 *FullPath; + CHAR16 *TempSpot; + UINTN Length; + CONST CHAR16 *NewName; + + Length = 0; + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + PathName = NULL; + CurDir = NULL; + FullPath = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // Fix local copies of the protocol pointers + // + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"vol", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } + + if (ShellCommandLineGetCount(Package) > 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"vol"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + PathName = ShellCommandLineGetRawValue(Package, 1); + if (PathName == NULL) { + CurDir = gEfiShellProtocol->GetCurDir(NULL); + if (CurDir == NULL) { + ShellStatus = SHELL_NOT_FOUND; + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"vol"); + } else { + PathName = CurDir; + } + } + if (PathName != NULL) { + TempSpot = StrStr(PathName, L":"); + if (TempSpot != NULL) { + *TempSpot = CHAR_NULL; + } + TempSpot = StrStr(PathName, L"\\"); + if (TempSpot != NULL) { + *TempSpot = CHAR_NULL; + } + StrnCatGrow(&FullPath, &Length, PathName, 0); + StrnCatGrow(&FullPath, &Length, L":\\", 0); + DeleteMode = ShellCommandLineGetFlag(Package, L"-d"); + NewName = ShellCommandLineGetValue(Package, L"-n"); + if (DeleteMode && ShellCommandLineGetFlag(Package, L"-n")) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CONFLICT), gShellLevel2HiiHandle, L"vol", L"-d", L"-n"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetFlag(Package, L"-n") && NewName == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellLevel2HiiHandle, L"vol", L"-n"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (NewName != NULL && StrLen(NewName) > 11) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellLevel2HiiHandle, L"vol", NewName, L"-n"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellStatus == SHELL_SUCCESS) { + ShellStatus = HandleVol( + FullPath, + DeleteMode, + NewName + ); + } + } + } + } + + SHELL_FREE_NON_NULL(FullPath); + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + + return (ShellStatus); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Alias.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Alias.c new file mode 100644 index 00000000..dd601520 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Alias.c @@ -0,0 +1,280 @@ +/** @file + Main file for Alias shell level 3 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel3CommandsLib.h" + +#include + +/** + Print out single alias registered with the Shell. + + @param[in] Alias Points to the NULL-terminated shell alias. + If this parameter is NULL, then all + aliases will be returned in ReturnedData. + @retval SHELL_SUCCESS the printout was sucessful +**/ +SHELL_STATUS +PrintSingleShellAlias( + IN CONST CHAR16 *Alias + ) +{ + CONST CHAR16 *ConstAliasVal; + SHELL_STATUS ShellStatus; + BOOLEAN Volatile; + + ShellStatus = SHELL_SUCCESS; + ConstAliasVal = gEfiShellProtocol->GetAlias (Alias, &Volatile); + if (ConstAliasVal == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel3HiiHandle, L"alias", Alias); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + if (ShellCommandIsOnAliasList (Alias)) { + Volatile = FALSE; + } + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_ALIAS_OUTPUT), gShellLevel3HiiHandle, !Volatile ? L' ' : L'*', Alias, ConstAliasVal); + } + return ShellStatus; +} + +/** + Print out each alias registered with the Shell. + + @retval STATUS_SUCCESS the printout was sucessful + @return any return code from GetNextVariableName except EFI_NOT_FOUND +**/ +SHELL_STATUS +PrintAllShellAlias( + VOID + ) +{ + CONST CHAR16 *ConstAllAliasList; + CHAR16 *Alias; + CHAR16 *Walker; + + ConstAllAliasList = gEfiShellProtocol->GetAlias(NULL, NULL); + if (ConstAllAliasList == NULL) { + return (SHELL_SUCCESS); + } + Alias = AllocateZeroPool(StrSize(ConstAllAliasList)); + if (Alias == NULL) { + return (SHELL_OUT_OF_RESOURCES); + } + Walker = (CHAR16*)ConstAllAliasList; + + do { + CopyMem(Alias, Walker, StrSize(Walker)); + Walker = StrStr(Alias, L";"); + if (Walker != NULL) { + Walker[0] = CHAR_NULL; + Walker = Walker + 1; + } + PrintSingleShellAlias(Alias); + } while (Walker != NULL && Walker[0] != CHAR_NULL); + + FreePool(Alias); + + return (SHELL_SUCCESS); +} + +/** + Changes a shell command alias. + + This function creates an alias for a shell command or if Alias is NULL it will delete an existing alias. + + + @param[in] Command Points to the NULL-terminated shell command or existing alias. + @param[in] Alias Points to the NULL-terminated alias for the shell command. If this is NULL, and + Command refers to an alias, that alias will be deleted. + @param[in] Replace If TRUE and the alias already exists, then the existing alias will be replaced. If + FALSE and the alias already exists, then the existing alias is unchanged and + EFI_ACCESS_DENIED is returned. + @param[in] Volatile if TRUE the Alias being set will be stored in a volatile fashion. if FALSE the + Alias being set will be stored in a non-volatile fashion. + + @retval SHELL_SUCCESS Alias created or deleted successfully. + @retval SHELL_NOT_FOUND the Alias intended to be deleted was not found + @retval SHELL_ACCESS_DENIED The alias is a built-in alias or already existed and Replace was set to + FALSE. + @retval SHELL_DEVICE_ERROR Command is null or the empty string. +**/ +SHELL_STATUS +ShellLevel3CommandsLibSetAlias( + IN CONST CHAR16 *Command, + IN CONST CHAR16 *Alias, + IN BOOLEAN Replace, + IN BOOLEAN Volatile + ) +{ + SHELL_STATUS ShellStatus; + EFI_STATUS Status; + + ShellStatus = SHELL_SUCCESS; + Status = gEfiShellProtocol->SetAlias (Command, Alias, Replace, Volatile); + if (EFI_ERROR(Status)) { + if (Status == EFI_ACCESS_DENIED) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellLevel3HiiHandle, L"alias"); + ShellStatus = SHELL_ACCESS_DENIED; + } else if (Status == EFI_NOT_FOUND) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_NOT_FOUND), gShellLevel3HiiHandle, L"alias", Command); + ShellStatus = SHELL_NOT_FOUND; + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel3HiiHandle, L"alias", Status); + ShellStatus = SHELL_DEVICE_ERROR; + } + } + return ShellStatus; +} + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-v", TypeFlag}, + {L"-d", TypeValue}, + {NULL, TypeMax} + }; + +/** + Function for 'alias' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunAlias ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CONST CHAR16 *Param1; + CONST CHAR16 *Param2; + CONST CHAR16 *ParamStrD; + CHAR16 *CleanParam2; + BOOLEAN DeleteFlag; + BOOLEAN VolatileFlag; + + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + CleanParam2 = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, L"alias", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + Param1 = ShellCommandLineGetRawValue(Package, 1); + Param2 = ShellCommandLineGetRawValue(Package, 2); + + DeleteFlag = ShellCommandLineGetFlag (Package, L"-d"); + VolatileFlag = ShellCommandLineGetFlag (Package, L"-v"); + + if (Param2 != NULL) { + CleanParam2 = AllocateCopyPool (StrSize(Param2), Param2); + if (CleanParam2 == NULL) { + ShellCommandLineFreeVarList (Package); + return SHELL_OUT_OF_RESOURCES; + } + + if (CleanParam2[0] == L'\"' && CleanParam2[StrLen(CleanParam2)-1] == L'\"') { + CleanParam2[StrLen(CleanParam2)-1] = L'\0'; + CopyMem (CleanParam2, CleanParam2 + 1, StrSize(CleanParam2) - sizeof(CleanParam2[0])); + } + } + + if (!DeleteFlag && !VolatileFlag) { + switch (ShellCommandLineGetCount (Package)) { + case 1: + // + // "alias" + // + ShellStatus = PrintAllShellAlias (); + break; + case 2: + // + // "alias Param1" + // + ShellStatus = PrintSingleShellAlias (Param1); + break; + case 3: + // + // "alias Param1 CleanParam2" + // + ShellStatus = ShellLevel3CommandsLibSetAlias (CleanParam2, Param1, FALSE, VolatileFlag); + break; + default: + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel3HiiHandle, L"alias"); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } else if (DeleteFlag) { + if (VolatileFlag || ShellCommandLineGetCount (Package) > 1) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel3HiiHandle, L"alias"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ParamStrD = ShellCommandLineGetValue (Package, L"-d"); + if (ParamStrD == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel3HiiHandle, L"alias"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // Delete an alias: "alias -d ParamStrD" + // + ShellStatus = ShellLevel3CommandsLibSetAlias (ParamStrD, NULL, TRUE, FALSE); + } + } + } else { + // + // Set volatile alias. + // + ASSERT (VolatileFlag); + ASSERT (!DeleteFlag); + switch (ShellCommandLineGetCount (Package)) { + case 1: + case 2: + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel3HiiHandle, L"alias"); + ShellStatus = SHELL_INVALID_PARAMETER; + break; + case 3: + // + // "alias -v Param1 CleanParam2" + // + ShellStatus = ShellLevel3CommandsLibSetAlias (CleanParam2, Param1, FALSE, VolatileFlag); + break; + default: + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel3HiiHandle, L"alias"); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + } + + SHELL_FREE_NON_NULL (CleanParam2); + return (ShellStatus); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Cls.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Cls.c new file mode 100644 index 00000000..ad382436 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Cls.c @@ -0,0 +1,224 @@ +/** @file + Main file for attrib shell level 2 function. + + (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+ (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel3CommandsLib.h" + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-sfo", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'cls' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunCls ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + UINTN Background; + UINTN Foreground; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CONST CHAR16 *BackColorStr; + CONST CHAR16 *ForeColorStr; + + // + // Initialize variables + // + ShellStatus = SHELL_SUCCESS; + ProblemParam = NULL; + Background = 0; + Foreground = 0; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, L"cls", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } else if (ShellCommandLineGetFlag (Package, L"-sfo")) { + if (ShellCommandLineGetCount (Package) > 1) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel3HiiHandle, L"cls"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Background = (gST->ConOut->Mode->Attribute >> 4) & 0x7; + Foreground = gST->ConOut->Mode->Attribute & 0x0F; + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_SFO_HEADER), gShellLevel3HiiHandle, L"cls"); + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_CLS_OUTPUT_SFO), + gShellLevel3HiiHandle, + gST->ConOut->Mode->Attribute, + Foreground, + Background + ); + } + } else { + // + // If there are 0 value parameters, clear sceen + // + BackColorStr = ShellCommandLineGetRawValue (Package, 1); + ForeColorStr = ShellCommandLineGetRawValue (Package, 2); + + if (BackColorStr == NULL && ForeColorStr == NULL) { + // + // clear screen + // + gST->ConOut->ClearScreen (gST->ConOut); + } else if (ShellCommandLineGetCount (Package) > 3) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel3HiiHandle, L"cls"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + if (BackColorStr != NULL) { + if ((ShellStrToUintn (BackColorStr) > 7) || (StrLen (BackColorStr) > 1) || (!ShellIsDecimalDigitCharacter (*BackColorStr))) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel3HiiHandle, L"cls", BackColorStr); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + switch (ShellStrToUintn (BackColorStr)) { + case 0: + Background = EFI_BACKGROUND_BLACK; + break; + case 1: + Background = EFI_BACKGROUND_BLUE; + break; + case 2: + Background = EFI_BACKGROUND_GREEN; + break; + case 3: + Background = EFI_BACKGROUND_CYAN; + break; + case 4: + Background = EFI_BACKGROUND_RED; + break; + case 5: + Background = EFI_BACKGROUND_MAGENTA; + break; + case 6: + Background = EFI_BACKGROUND_BROWN; + break; + case 7: + Background = EFI_BACKGROUND_LIGHTGRAY; + break; + } + + if (ForeColorStr != NULL) { + if ((ShellStrToUintn (ForeColorStr) > 15) || (StrLen (ForeColorStr) > 2) || (!ShellIsDecimalDigitCharacter (*ForeColorStr))) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel3HiiHandle, L"cls", ForeColorStr); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + switch (ShellStrToUintn (ForeColorStr)) { + case 0: + Foreground = EFI_BLACK; + break; + case 1: + Foreground = EFI_BLUE; + break; + case 2: + Foreground = EFI_GREEN; + break; + case 3: + Foreground = EFI_CYAN; + break; + case 4: + Foreground = EFI_RED; + break; + case 5: + Foreground = EFI_MAGENTA; + break; + case 6: + Foreground = EFI_BROWN; + break; + case 7: + Foreground = EFI_LIGHTGRAY; + break; + case 8: + Foreground = EFI_DARKGRAY; + break; + case 9: + Foreground = EFI_LIGHTBLUE; + break; + case 10: + Foreground = EFI_LIGHTGREEN; + break; + case 11: + Foreground = EFI_LIGHTCYAN; + break; + case 12: + Foreground = EFI_LIGHTRED; + break; + case 13: + Foreground = EFI_LIGHTMAGENTA; + break; + case 14: + Foreground = EFI_YELLOW; + break; + case 15: + Foreground = EFI_WHITE; + break; + } + } + } else { + // + // Since foreground color is not modified, so retain + // existing foreground color without any change to it. + // + Foreground = gST->ConOut->Mode->Attribute & 0x0F; + } + + if (ShellStatus == SHELL_SUCCESS) { + Status = gST->ConOut->SetAttribute (gST->ConOut, (Foreground | Background) & 0x7F); + ASSERT_EFI_ERROR (Status); + Status = gST->ConOut->ClearScreen (gST->ConOut); + ASSERT_EFI_ERROR (Status); + } + } + } + } + } + } + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + + // + // return the status + // + return (ShellStatus); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Echo.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Echo.c new file mode 100644 index 00000000..f229287c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Echo.c @@ -0,0 +1,115 @@ +/** @file + Main file for Echo shell level 3 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel3CommandsLib.h" + +#include + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-on", TypeFlag}, + {L"-off", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'echo' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunEcho ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + SHELL_STATUS ShellStatus; + UINTN ParamCount; + CHAR16 *ProblemParam; + UINTN Size; + CHAR16 *PrintString; + + Size = 0; + ProblemParam = NULL; + PrintString = NULL; + ShellStatus = SHELL_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParseEx (ParamList, &Package, &ProblemParam, TRUE, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, L"echo", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } + if (ShellCommandLineGetFlag(Package, L"-on")) { + // + // Turn it on + // + ShellCommandSetEchoState(TRUE); + } else if (ShellCommandLineGetFlag(Package, L"-off")) { + // + // turn it off + // + ShellCommandSetEchoState(FALSE); + } else if (ShellCommandLineGetRawValue(Package, 1) == NULL) { + // + // output its current state + // + if (ShellCommandGetEchoState()) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_ECHO_ON), gShellLevel3HiiHandle); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_ECHO_OFF), gShellLevel3HiiHandle); + } + } else { + // + // print the line + // + for ( ParamCount = 1 + ; ShellCommandLineGetRawValue(Package, ParamCount) != NULL + ; ParamCount++ + ) { + StrnCatGrow(&PrintString, &Size, ShellCommandLineGetRawValue(Package, ParamCount), 0); + if (ShellCommandLineGetRawValue(Package, ParamCount+1) != NULL) { + StrnCatGrow(&PrintString, &Size, L" ", 0); + } + } + ShellPrintEx(-1, -1, L"%s\r\n", PrintString); + SHELL_FREE_NON_NULL(PrintString); + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + } + + return (ShellStatus); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/GetMtc.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/GetMtc.c new file mode 100644 index 00000000..60b57385 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/GetMtc.c @@ -0,0 +1,91 @@ +/** @file + Main file for GetMtc shell level 3 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel3CommandsLib.h" + +#include + +/** + Function for 'getmtc' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunGetMtc ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + UINT64 Mtc; + + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, L"getmtc", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } else if (ShellCommandLineGetRawValue(Package, 1) != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel3HiiHandle, L"getmtc"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // Get the monotonic counter count + // + Status = gBS->GetNextMonotonicCount(&Mtc); + if (Status == EFI_DEVICE_ERROR) { + ShellStatus = SHELL_DEVICE_ERROR; + } else if (Status == EFI_SECURITY_VIOLATION) { + ShellStatus = SHELL_SECURITY_VIOLATION; + } else if (EFI_ERROR(Status)) { + ShellStatus = SHELL_DEVICE_ERROR; + } + + // + // print it... + // + if (ShellStatus == SHELL_SUCCESS) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GET_MTC_OUTPUT), gShellLevel3HiiHandle, Mtc); + } + } + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + } + + return (ShellStatus); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Help.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Help.c new file mode 100644 index 00000000..2eca13f2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Help.c @@ -0,0 +1,468 @@ +/** @file + Main file for Help shell level 3 function. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ Copyright (c) 2014, ARM Limited. All rights reserved.
+ (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel3CommandsLib.h" + +#include +#include + +#include + +/** + function to insert string items into a list in the correct alphabetical place + + the resultant list is a double NULL terminated list of NULL terminated strings. + + upon successful return the memory must be caller freed (unless passed back in + via a loop where it will get reallocated). + + @param[in,out] DestList double pointer to the list. may be NULL. + @param[in,out] DestSize pointer to the size of list. may be 0, if DestList is NULL. + @param[in] Item the item to insert. + + @retval EFI_SUCCESS the operation was successful. +**/ +EFI_STATUS +LexicalInsertIntoList( + IN OUT CHAR16 **DestList, + IN OUT UINTN *DestSize, + IN CONST CHAR16 *Item + ) +{ + CHAR16 *NewList; + INTN LexicalMatchValue; + CHAR16 *LexicalSpot; + UINTN SizeOfAddedNameInBytes; + + // + // If there are none, then just return with success + // + if (Item == NULL || *Item == CHAR_NULL || StrLen(Item)==0) { + return (EFI_SUCCESS); + } + + NewList = *DestList; + + SizeOfAddedNameInBytes = StrSize(Item); + NewList = ReallocatePool(*DestSize, (*DestSize) + SizeOfAddedNameInBytes, NewList); + (*DestSize) = (*DestSize) + SizeOfAddedNameInBytes; + + // + // Find the correct spot in the list + // + for (LexicalSpot = NewList + ; LexicalSpot != NULL && LexicalSpot < NewList + (*DestSize) + ; LexicalSpot += StrLen(LexicalSpot) + 1 + ) { + // + // Get Lexical Comparison Value between PrevCommand and Command list entry + // + LexicalMatchValue = gUnicodeCollation->StriColl ( + gUnicodeCollation, + (CHAR16 *)LexicalSpot, + (CHAR16 *)Item + ); + // + // The new item goes before this one. + // + if (LexicalMatchValue > 0 || StrLen(LexicalSpot) == 0) { + if (StrLen(LexicalSpot) != 0) { + // + // Move this and all other items out of the way + // + CopyMem( + LexicalSpot + (SizeOfAddedNameInBytes/sizeof(CHAR16)), + LexicalSpot, + (*DestSize) - SizeOfAddedNameInBytes - ((LexicalSpot - NewList) * sizeof(CHAR16)) + ); + } + + // + // Stick this one in place + // + StrCpyS(LexicalSpot, SizeOfAddedNameInBytes/sizeof(CHAR16), Item); + break; + } + } + + *DestList = NewList; + return (EFI_SUCCESS); +} + +/** + function to add each command name from the linked list to the string list. + + the resultant list is a double NULL terminated list of NULL terminated strings. + + @param[in,out] DestList double pointer to the list. may be NULL. + @param[in,out] DestSize pointer to the size of list. may be 0, if DestList is NULL. + @param[in] SourceList the double linked list of commands. + + @retval EFI_SUCCESS the operation was successful. +**/ +EFI_STATUS +CopyListOfCommandNames( + IN OUT CHAR16 **DestList, + IN OUT UINTN *DestSize, + IN CONST COMMAND_LIST *SourceList + ) +{ + CONST COMMAND_LIST *Node; + + for ( Node = (COMMAND_LIST*)GetFirstNode(&SourceList->Link) + ; SourceList != NULL && !IsListEmpty(&SourceList->Link) && !IsNull(&SourceList->Link, &Node->Link) + ; Node = (COMMAND_LIST*)GetNextNode(&SourceList->Link, &Node->Link) + ) { + LexicalInsertIntoList(DestList, DestSize, Node->CommandString); + } + return (EFI_SUCCESS); +} + +/** + function to add each dynamic command name to the string list. + + the resultant list is a double NULL terminated list of NULL terminated strings. + + @param[in,out] DestList double pointer to the list. may be NULL. + @param[in,out] DestSize pointer to the size of list. may be 0, if DestList is NULL. + + @retval EFI_SUCCESS the operation was successful. + @return an error from HandleProtocol +**/ +STATIC +EFI_STATUS +CopyListOfCommandNamesWithDynamic( + IN OUT CHAR16** DestList, + IN OUT UINTN *DestSize + ) +{ + EFI_HANDLE *CommandHandleList; + CONST EFI_HANDLE *NextCommand; + EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand; + EFI_STATUS Status; + + CommandHandleList = GetHandleListByProtocol(&gEfiShellDynamicCommandProtocolGuid); + + // + // If there are none, then just return with success + // + if (CommandHandleList == NULL) { + return (EFI_SUCCESS); + } + + Status = EFI_SUCCESS; + + // + // Append those to the list. + // + for (NextCommand = CommandHandleList ; *NextCommand != NULL && !EFI_ERROR(Status) ; NextCommand++) { + Status = gBS->HandleProtocol( + *NextCommand, + &gEfiShellDynamicCommandProtocolGuid, + (VOID **)&DynamicCommand + ); + + if (EFI_ERROR(Status)) { + continue; + } + + Status = LexicalInsertIntoList(DestList, DestSize, DynamicCommand->CommandName); + } + + SHELL_FREE_NON_NULL(CommandHandleList); + return (Status); +} + + +/** + Attempt to print help from a dynamically added command. + + @param[in] CommandToGetHelpOn The unicode name of the command that help is + requested on. + @param[in] SectionToGetHelpOn Pointer to the section specifier(s). + @param[in] PrintCommandText Print the command followed by the help content + or just help. + + @retval EFI_SUCCESS The help was displayed + @retval EFI_NOT_FOUND The command name could not be found + @retval EFI_DEVICE_ERROR The help data format was incorrect. +**/ +EFI_STATUS +PrintDynamicCommandHelp( + IN CONST CHAR16 *CommandToGetHelpOn, + IN CONST CHAR16 *SectionToGetHelpOn, + IN BOOLEAN PrintCommandText + ) +{ + EFI_STATUS Status; + BOOLEAN Found; + EFI_HANDLE *CommandHandleList; + EFI_HANDLE *NextCommand; + EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand; + + Status = EFI_NOT_FOUND; + Found = FALSE; + CommandHandleList = NULL; + + CommandHandleList = GetHandleListByProtocol(&gEfiShellDynamicCommandProtocolGuid); + + if (CommandHandleList == NULL) { + // + // not found or out of resources + // + return Status; + } + + for (NextCommand = CommandHandleList; *NextCommand != NULL; NextCommand++) { + Status = gBS->HandleProtocol( + *NextCommand, + &gEfiShellDynamicCommandProtocolGuid, + (VOID **)&DynamicCommand + ); + + if (EFI_ERROR(Status)) { + continue; + } + + // + // Check execution break flag when printing multiple command help information. + // + if (ShellGetExecutionBreakFlag ()) { + break; + } + + if ((gUnicodeCollation->MetaiMatch (gUnicodeCollation, (CHAR16 *)DynamicCommand->CommandName, (CHAR16*)CommandToGetHelpOn)) || + (gEfiShellProtocol->GetAlias (CommandToGetHelpOn, NULL) != NULL && (gUnicodeCollation->MetaiMatch (gUnicodeCollation, (CHAR16 *)DynamicCommand->CommandName, (CHAR16*)(gEfiShellProtocol->GetAlias(CommandToGetHelpOn, NULL)))))) { + // Print as Shell Help if in ManPage format. + Status = ShellPrintHelp (DynamicCommand->CommandName, SectionToGetHelpOn, + PrintCommandText); + if (Status == EFI_DEVICE_ERROR) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_HELP_INV), + gShellLevel3HiiHandle, DynamicCommand->CommandName); + } else if (EFI_ERROR(Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_HELP_NF), + gShellLevel3HiiHandle, DynamicCommand->CommandName); + } else { + Found = TRUE; + } + } + } + + SHELL_FREE_NON_NULL(CommandHandleList); + + return (Found ? EFI_SUCCESS : Status); + +} + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-usage", TypeFlag}, + {L"-section", TypeMaxValue}, + {L"-verbose", TypeFlag}, + {L"-v", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'help' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunHelp ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CHAR16 *SortedCommandList; + CONST CHAR16 *CurrentCommand; + CHAR16 *CommandToGetHelpOn; + CHAR16 *SectionToGetHelpOn; + CHAR16 *HiiString; + BOOLEAN Found; + BOOLEAN PrintCommandText; + UINTN SortedCommandListSize; + + PrintCommandText = TRUE; + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + CommandToGetHelpOn = NULL; + SectionToGetHelpOn = NULL; + SortedCommandList = NULL; + Found = FALSE; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, L"help", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // Check for conflicting parameters. + // + if (ShellCommandLineGetFlag(Package, L"-usage") + &&ShellCommandLineGetFlag(Package, L"-section") + &&(ShellCommandLineGetFlag(Package, L"-verbose") || ShellCommandLineGetFlag(Package, L"-v")) + ){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CON), gShellLevel3HiiHandle, L"help"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetRawValue(Package, 2) != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel3HiiHandle, L"help"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // Get the command name we are getting help on + // + ASSERT(CommandToGetHelpOn == NULL); + StrnCatGrow(&CommandToGetHelpOn, NULL, ShellCommandLineGetRawValue(Package, 1), 0); + if (CommandToGetHelpOn == NULL && ShellCommandLineGetFlag(Package, L"-?")) { + // + // If we dont have a command and we got a simple -? + // we are looking for help on help command. + // + StrnCatGrow(&CommandToGetHelpOn, NULL, L"help", 0); + } + + if (CommandToGetHelpOn == NULL) { + StrnCatGrow(&CommandToGetHelpOn, NULL, L"*", 0); + ASSERT(SectionToGetHelpOn == NULL); + StrnCatGrow(&SectionToGetHelpOn, NULL, L"NAME", 0); + } else { + PrintCommandText = FALSE; + ASSERT(SectionToGetHelpOn == NULL); + // + // Get the section name for the given command name + // + if (ShellCommandLineGetFlag(Package, L"-section")) { + StrnCatGrow(&SectionToGetHelpOn, NULL, ShellCommandLineGetValue(Package, L"-section"), 0); + } else if (ShellCommandLineGetFlag(Package, L"-usage")) { + StrnCatGrow(&SectionToGetHelpOn, NULL, L"NAME,SYNOPSIS", 0); + } else if (ShellCommandLineGetFlag(Package, L"-verbose") || ShellCommandLineGetFlag(Package, L"-v")) { + } else { + // + // The output of help will display NAME, SYNOPSIS, OPTIONS, DESCRIPTION, and EXAMPLES sections. + // + StrnCatGrow (&SectionToGetHelpOn, NULL, L"NAME,SYNOPSIS,OPTIONS,DESCRIPTION,EXAMPLES", 0); + } + } + + if (gUnicodeCollation->StriColl(gUnicodeCollation, CommandToGetHelpOn, L"special") == 0) { + // + // we need info on the special characters + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HELP_SC_HEADER), gShellLevel3HiiHandle); + HiiString = HiiGetString(gShellLevel3HiiHandle, STRING_TOKEN(STR_HELP_SC_DATA), NULL); + ShellPrintEx(-1, -1, L"%s", HiiString); + FreePool(HiiString); + Found = TRUE; + } else { + SortedCommandList = NULL; + SortedCommandListSize = 0; + CopyListOfCommandNames(&SortedCommandList, &SortedCommandListSize, ShellCommandGetCommandList(TRUE)); + CopyListOfCommandNamesWithDynamic(&SortedCommandList, &SortedCommandListSize); + + for (CurrentCommand = SortedCommandList + ; CurrentCommand != NULL && CurrentCommand < SortedCommandList + SortedCommandListSize/sizeof(CHAR16) && *CurrentCommand != CHAR_NULL + ; CurrentCommand += StrLen(CurrentCommand) + 1 + ) { + // + // Checking execution break flag when print multiple command help information. + // + if (ShellGetExecutionBreakFlag ()) { + break; + } + + if ((gUnicodeCollation->MetaiMatch(gUnicodeCollation, (CHAR16*)CurrentCommand, CommandToGetHelpOn)) || + (gEfiShellProtocol->GetAlias(CommandToGetHelpOn, NULL) != NULL && (gUnicodeCollation->MetaiMatch(gUnicodeCollation, (CHAR16*)CurrentCommand, (CHAR16*)(gEfiShellProtocol->GetAlias(CommandToGetHelpOn, NULL)))))) { + // + // We have a command to look for help on. + // + Status = ShellPrintHelp(CurrentCommand, SectionToGetHelpOn, PrintCommandText); + if (EFI_ERROR(Status)) { + // + // now try to match against the dynamic command list and print help + // + Status = PrintDynamicCommandHelp (CurrentCommand, SectionToGetHelpOn, PrintCommandText); + } + if (Status == EFI_DEVICE_ERROR) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HELP_INV), gShellLevel3HiiHandle, CurrentCommand); + } else if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HELP_NF), gShellLevel3HiiHandle, CurrentCommand); + } else { + Found = TRUE; + } + } + } + + // + // Search the .man file for Shell applications (Shell external commands). + // + if (!Found) { + Status = ShellPrintHelp(CommandToGetHelpOn, SectionToGetHelpOn, FALSE); + if (Status == EFI_DEVICE_ERROR) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HELP_INV), gShellLevel3HiiHandle, CommandToGetHelpOn); + } else if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HELP_NF), gShellLevel3HiiHandle, CommandToGetHelpOn); + } else { + Found = TRUE; + } + } + } + + if (!Found) { + ShellStatus = SHELL_NOT_FOUND; + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + } + } + + if (CommandToGetHelpOn != NULL && StrCmp(CommandToGetHelpOn, L"*") == 0){ + // + // If '*' then the command entered was 'Help' without qualifiers, This footer + // provides additional info on help switches + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HELP_FOOTER), gShellLevel3HiiHandle); + } + if (CommandToGetHelpOn != NULL) { + FreePool(CommandToGetHelpOn); + } + if (SectionToGetHelpOn != NULL) { + FreePool(SectionToGetHelpOn); + } + SHELL_FREE_NON_NULL(SortedCommandList); + + return (ShellStatus); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Pause.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Pause.c new file mode 100644 index 00000000..2a72c4f1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Pause.c @@ -0,0 +1,101 @@ +/** @file + Main file for Pause shell level 3 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel3CommandsLib.h" + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-q", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'pause' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunPause ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + SHELL_PROMPT_RESPONSE *Resp; + + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + Resp = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + if (!gEfiShellProtocol->BatchIsActive()) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel3HiiHandle, L"pause"); + return (SHELL_UNSUPPORTED); + } + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, L"pause", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } else if (ShellCommandLineGetRawValue(Package, 1) != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel3HiiHandle, L"pause"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + if (!ShellCommandLineGetFlag(Package, L"-q")) { + Status = ShellPromptForResponseHii(ShellPromptResponseTypeQuitContinue, STRING_TOKEN (STR_PAUSE_PROMPT), gShellLevel3HiiHandle, (VOID**)&Resp); + } else { + Status = ShellPromptForResponse(ShellPromptResponseTypeQuitContinue, NULL, (VOID**)&Resp); + } + + if (EFI_ERROR(Status) || Resp == NULL || *Resp == ShellPromptResponseQuit) { + ShellCommandRegisterExit(TRUE, 0); + ShellStatus = SHELL_ABORTED; + } + + if (Resp != NULL) { + FreePool(Resp); + } + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + } + + + return (ShellStatus); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Touch.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Touch.c new file mode 100644 index 00000000..4fb312ff --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Touch.c @@ -0,0 +1,286 @@ +/** @file + Main file for Touch shell level 3 function. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel3CommandsLib.h" + +#include + +/** + Do the touch operation on a single handle. + + @param[in] Handle The handle to update the date/time on. + + @retval EFI_ACCESS_DENIED The file referenced by Handle is read only. + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +TouchFileByHandle ( + IN SHELL_FILE_HANDLE Handle + ) +{ + EFI_STATUS Status; + EFI_FILE_INFO *FileInfo; + + FileInfo = gEfiShellProtocol->GetFileInfo(Handle); + if ((FileInfo->Attribute & EFI_FILE_READ_ONLY) != 0){ + return (EFI_ACCESS_DENIED); + } + Status = gRT->GetTime(&FileInfo->ModificationTime, NULL); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, L"gRT->GetTime", Status); + return (SHELL_DEVICE_ERROR); + } + + CopyMem(&FileInfo->LastAccessTime, &FileInfo->ModificationTime, sizeof(EFI_TIME)); + + Status = gEfiShellProtocol->SetFileInfo(Handle, FileInfo); + + FreePool(FileInfo); + + return (Status); +} + +/** + Touch a given file and potantially recurse down if it was a directory. + + @param[in] Name The name of this file. + @param[in] FS The name of the file system this file is on. + @param[in] Handle The handle of this file already opened. + @param[in] Rec TRUE to recurse if possible. + + @retval EFI_INVALID_PARAMETER A parameter was invalid. + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +DoTouchByHandle ( + IN CONST CHAR16 *Name, + IN CHAR16 *FS, + IN SHELL_FILE_HANDLE Handle, + IN BOOLEAN Rec + ) +{ + EFI_STATUS Status; + EFI_SHELL_FILE_INFO *FileList; + EFI_SHELL_FILE_INFO *Walker; + CHAR16 *TempSpot; + + Status = EFI_SUCCESS; + FileList = NULL; + Walker = NULL; + + if (FS == NULL) { + FS = StrnCatGrow(&FS, NULL, Name, 0); + if (FS != NULL) { + TempSpot = StrStr(FS, L"\\"); + if (TempSpot != NULL) { + *TempSpot = CHAR_NULL; + } + } + } + if (FS == NULL) { + return (EFI_INVALID_PARAMETER); + } + + // + // do it + // + Status = TouchFileByHandle(Handle); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellLevel3HiiHandle, L"touch", Name); + return (Status); + } + + // + // if it's a directory recurse... + // + if (FileHandleIsDirectory(Handle) == EFI_SUCCESS && Rec) { + // + // get each file under this directory + // + if (EFI_ERROR(gEfiShellProtocol->FindFilesInDir(Handle, &FileList))) { + Status = EFI_INVALID_PARAMETER; + } + + // + // recurse on each + // + for (Walker = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link) + ; FileList != NULL && !IsNull(&FileList->Link, &Walker->Link) && !EFI_ERROR(Status) + ; Walker = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Walker->Link) + ){ + if ( (StrCmp(Walker->FileName, L".") != 0) + && (StrCmp(Walker->FileName, L"..") != 0) + ){ + // + // Open the file since we need that handle. + // + Status = gEfiShellProtocol->OpenFileByName (Walker->FullName, &Walker->Handle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellLevel3HiiHandle, L"touch", Walker->FullName); + Status = EFI_ACCESS_DENIED; + } else { + Status = DoTouchByHandle(Walker->FullName, FS, Walker->Handle, TRUE); + gEfiShellProtocol->CloseFile(Walker->Handle); + Walker->Handle = NULL; + } + } + } + + // + // free stuff + // + if (FileList != NULL && EFI_ERROR(gEfiShellProtocol->FreeFileList(&FileList))) { + Status = EFI_INVALID_PARAMETER; + } + } + + return (Status); +} + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-r", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'touch' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunTouch ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + CONST CHAR16 *Param; + SHELL_STATUS ShellStatus; + UINTN ParamCount; + EFI_SHELL_FILE_INFO *FileList; + EFI_SHELL_FILE_INFO *Node; + + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + ParamCount = 0; + FileList = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, L"touch", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } + if (ShellCommandLineGetRawValue(Package, 1) == NULL) { + // + // we insufficient parameters + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel3HiiHandle, L"touch"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // get a list with each file specified by parameters + // if parameter is a directory then add all the files below it to the list + // + for ( ParamCount = 1, Param = ShellCommandLineGetRawValue(Package, ParamCount) + ; Param != NULL + ; ParamCount++, Param = ShellCommandLineGetRawValue(Package, ParamCount) + ){ + Status = ShellOpenFileMetaArg((CHAR16*)Param, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, &FileList); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel3HiiHandle, L"touch", (CHAR16*)Param); + ShellStatus = SHELL_NOT_FOUND; + break; + } + // + // make sure we completed the param parsing sucessfully... + // Also make sure that any previous action was sucessful + // + if (ShellStatus == SHELL_SUCCESS) { + // + // check that we have at least 1 file + // + if (FileList == NULL || IsListEmpty(&FileList->Link)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel3HiiHandle, L"touch", Param); + continue; + } else { + // + // loop through the list and make sure we are not aborting... + // + for ( Node = (EFI_SHELL_FILE_INFO*)GetFirstNode(&FileList->Link) + ; !IsNull(&FileList->Link, &Node->Link) && !ShellGetExecutionBreakFlag() + ; Node = (EFI_SHELL_FILE_INFO*)GetNextNode(&FileList->Link, &Node->Link) + ){ + // + // make sure the file opened ok + // + if (EFI_ERROR(Node->Status)){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellLevel3HiiHandle, L"touch", Node->FileName); + ShellStatus = SHELL_NOT_FOUND; + continue; + } + + Status = DoTouchByHandle(Node->FullName, NULL, Node->Handle, ShellCommandLineGetFlag(Package, L"-r")); + if (EFI_ERROR(Status) && Status != EFI_ACCESS_DENIED) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellLevel3HiiHandle, L"touch", Node->FileName); + ShellStatus = SHELL_NOT_FOUND; + } + } + } + } + // + // Free the fileList + // + if (FileList != NULL && !IsListEmpty(&FileList->Link)) { + Status = ShellCloseFileMetaArg(&FileList); + ASSERT_EFI_ERROR(Status); + } + FileList = NULL; + } + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + } + + if (ShellGetExecutionBreakFlag()) { + return (SHELL_ABORTED); + } + + return (ShellStatus); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Type.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Type.c new file mode 100644 index 00000000..ae80e292 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Type.c @@ -0,0 +1,323 @@ +/** @file + Main file for Type shell level 3 function. + + (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel3CommandsLib.h" + +#include + +/** + Display a single file to StdOut. + + If both Ascii and UCS2 are FALSE attempt to discover the file type. + + @param[in] Handle The handle to the file to display. + @param[in] Ascii TRUE to force ASCII, FALSE othewise. + @param[in] UCS2 TRUE to force UCS2, FALSE othewise. + + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +TypeFileByHandle ( + IN SHELL_FILE_HANDLE Handle, + IN BOOLEAN Ascii, + IN BOOLEAN UCS2 + ) +{ + UINTN ReadSize; + VOID *Buffer; + VOID *AllocatedBuffer; + EFI_STATUS Status; + UINTN LoopVar; + UINTN LoopSize; + CHAR16 AsciiChar; + CHAR16 Ucs2Char; + + ReadSize = PcdGet32(PcdShellFileOperationSize); + AllocatedBuffer = AllocateZeroPool(ReadSize); + if (AllocatedBuffer == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + Status = ShellSetFilePosition(Handle, 0); + ASSERT_EFI_ERROR(Status); + + while (ReadSize == ((UINTN)PcdGet32(PcdShellFileOperationSize))) { + Buffer = AllocatedBuffer; + ZeroMem(Buffer, ReadSize); + Status = ShellReadFile(Handle, &ReadSize, Buffer); + if (EFI_ERROR(Status)){ + break; + } + + if (!(Ascii|UCS2)) { + if (*(UINT16*)Buffer == gUnicodeFileTag) { + UCS2 = TRUE; + } else { + Ascii = TRUE; + } + } + + if (Ascii) { + LoopSize = ReadSize; + for (LoopVar = 0 ; LoopVar < LoopSize ; LoopVar++) { + // + // The valid range of ASCII characters is 0x20-0x7E. + // Display "." when there is an invalid character. + // + AsciiChar = CHAR_NULL; + AsciiChar = ((CHAR8*)Buffer)[LoopVar]; + if (AsciiChar == '\r' || AsciiChar == '\n') { + // + // Allow Line Feed (LF) (0xA) & Carriage Return (CR) (0xD) + // characters to be displayed as is. + // + if ((AsciiChar == '\n' && LoopVar == 0) || + (AsciiChar == '\n' && ((CHAR8*)Buffer)[LoopVar-1] != '\r')) { + // + // In case file begin with single line Feed or Line Feed (0xA) is + // encountered & Carriage Return (0xD) was not previous character, + // print CR and LF. This is because Shell 2.0 requires carriage + // return with line feed for displaying each new line from left. + // + ShellPrintEx (-1, -1, L"\r\n"); + continue; + } + } else { + // + // For all other characters which are not printable, display '.' + // + if (AsciiChar < 0x20 || AsciiChar >= 0x7F) { + AsciiChar = '.'; + } + } + ShellPrintEx (-1, -1, L"%c", AsciiChar); + } + } else { + if (*(UINT16*)Buffer == gUnicodeFileTag) { + // + // For unicode files, skip displaying the byte order marker. + // + Buffer = ((UINT16*)Buffer) + 1; + LoopSize = (ReadSize / (sizeof (CHAR16))) - 1; + } else { + LoopSize = ReadSize / (sizeof (CHAR16)); + } + + for (LoopVar = 0 ; LoopVar < LoopSize ; LoopVar++) { + // + // An invalid range of characters is 0x0-0x1F. + // Display "." when there is an invalid character. + // + Ucs2Char = CHAR_NULL; + Ucs2Char = ((CHAR16*)Buffer)[LoopVar]; + if (Ucs2Char == '\r' || Ucs2Char == '\n') { + // + // Allow Line Feed (LF) (0xA) & Carriage Return (CR) (0xD) + // characters to be displayed as is. + // + if ((Ucs2Char == '\n' && LoopVar == 0) || + (Ucs2Char == '\n' && ((CHAR16*)Buffer)[LoopVar-1] != '\r')) { + // + // In case file begin with single line Feed or Line Feed (0xA) is + // encountered & Carriage Return (0xD) was not previous character, + // print CR and LF. This is because Shell 2.0 requires carriage + // return with line feed for displaying each new line from left. + // + ShellPrintEx (-1, -1, L"\r\n"); + continue; + } + } + else if (Ucs2Char < 0x20) { + // + // For all other characters which are not printable, display '.' + // + Ucs2Char = L'.'; + } + ShellPrintEx (-1, -1, L"%c", Ucs2Char); + } + } + + if (ShellGetExecutionBreakFlag()) { + break; + } + } + FreePool (AllocatedBuffer); + ShellPrintEx (-1, -1, L"\r\n"); + return (Status); +} + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-a", TypeFlag}, + {L"-u", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'type' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunType ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + CONST CHAR16 *Param; + SHELL_STATUS ShellStatus; + UINTN ParamCount; + EFI_SHELL_FILE_INFO *FileList; + EFI_SHELL_FILE_INFO *Node; + BOOLEAN AsciiMode; + BOOLEAN UnicodeMode; + + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + ParamCount = 0; + FileList = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, L"type", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } + AsciiMode = ShellCommandLineGetFlag(Package, L"-a"); + UnicodeMode = ShellCommandLineGetFlag(Package, L"-u"); + + if (AsciiMode && UnicodeMode) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel3HiiHandle, L"type", L"-a & -u"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetRawValue(Package, 1) == NULL) { + // + // we insufficient parameters + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel3HiiHandle, L"type"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // get a list with each file specified by parameters + // if parameter is a directory then add all the files below it to the list + // + for ( ParamCount = 1, Param = ShellCommandLineGetRawValue(Package, ParamCount) + ; Param != NULL + ; ParamCount++, Param = ShellCommandLineGetRawValue(Package, ParamCount) + ){ + Status = ShellOpenFileMetaArg((CHAR16*)Param, EFI_FILE_MODE_READ, &FileList); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellLevel3HiiHandle, L"type", (CHAR16*)Param); + ShellStatus = SHELL_NOT_FOUND; + break; + } + // + // make sure we completed the param parsing sucessfully... + // Also make sure that any previous action was sucessful + // + if (ShellStatus == SHELL_SUCCESS) { + // + // check that we have at least 1 file + // + if (FileList == NULL || IsListEmpty(&FileList->Link)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel3HiiHandle, L"type", Param); + continue; + } else { + // + // loop through the list and make sure we are not aborting... + // + for ( Node = (EFI_SHELL_FILE_INFO*)GetFirstNode(&FileList->Link) + ; !IsNull(&FileList->Link, &Node->Link) && !ShellGetExecutionBreakFlag() + ; Node = (EFI_SHELL_FILE_INFO*)GetNextNode(&FileList->Link, &Node->Link) + ){ + + if (ShellGetExecutionBreakFlag()) { + break; + } + + // + // make sure the file opened ok + // + if (EFI_ERROR(Node->Status)){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellLevel3HiiHandle, L"type", Node->FileName); + ShellStatus = SHELL_NOT_FOUND; + continue; + } + + // + // make sure its not a directory + // + if (FileHandleIsDirectory(Node->Handle) == EFI_SUCCESS) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_IS_DIR), gShellLevel3HiiHandle, L"type", Node->FileName); + ShellStatus = SHELL_NOT_FOUND; + continue; + } + + // + // do it + // + Status = TypeFileByHandle (Node->Handle, AsciiMode, UnicodeMode); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_TYP_ERROR), gShellLevel3HiiHandle, L"type", Node->FileName); + ShellStatus = SHELL_INVALID_PARAMETER; + } + ASSERT(ShellStatus == SHELL_SUCCESS); + } + } + } + // + // Free the fileList + // + if (FileList != NULL && !IsListEmpty(&FileList->Link)) { + Status = ShellCloseFileMetaArg(&FileList); + } + ASSERT_EFI_ERROR(Status); + FileList = NULL; + } + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + } + + if (ShellGetExecutionBreakFlag()) { + return (SHELL_ABORTED); + } + + return (ShellStatus); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.c new file mode 100644 index 00000000..bb1cf6f1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.c @@ -0,0 +1,95 @@ +/** @file + Main file for NULL named library for level 3 shell command functions. + + (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "UefiShellLevel3CommandsLib.h" + +CONST CHAR16 gShellLevel3FileName[] = L"ShellCommands"; +EFI_HII_HANDLE gShellLevel3HiiHandle = NULL; + +/** + return the filename to get help from is not using HII. + + @retval The filename. +**/ +CONST CHAR16* +EFIAPI +ShellCommandGetManFileNameLevel3 ( + VOID + ) +{ + return (gShellLevel3FileName); +} + +/** + Constructor for the Shell Level 3 Commands library. + + Install the handlers for level 3 UEFI Shell 2.0 commands. + + @param ImageHandle the image handle of the process + @param SystemTable the EFI System Table pointer + + @retval EFI_SUCCESS the shell command handlers were installed sucessfully + @retval EFI_UNSUPPORTED the shell level required was not found. +**/ +EFI_STATUS +EFIAPI +ShellLevel3CommandsLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + gShellLevel3HiiHandle = NULL; + // + // if shell level is less than 3 do nothing + // + if (PcdGet8(PcdShellSupportLevel) < 3) { + return (EFI_SUCCESS); + } + + gShellLevel3HiiHandle = HiiAddPackages (&gShellLevel3HiiGuid, gImageHandle, UefiShellLevel3CommandsLibStrings, NULL); + if (gShellLevel3HiiHandle == NULL) { + return (EFI_DEVICE_ERROR); + } + // + // install our shell command handlers that are always installed + // + // Note: that Time, Timezone, and Date are part of level 2 library + // + ShellCommandRegisterCommandName(L"type", ShellCommandRunType , ShellCommandGetManFileNameLevel3, 3, L"", TRUE , gShellLevel3HiiHandle, STRING_TOKEN(STR_GET_HELP_TYPE)); + ShellCommandRegisterCommandName(L"touch", ShellCommandRunTouch , ShellCommandGetManFileNameLevel3, 3, L"", TRUE , gShellLevel3HiiHandle, STRING_TOKEN(STR_GET_HELP_TOUCH)); + ShellCommandRegisterCommandName(L"ver", ShellCommandRunVer , ShellCommandGetManFileNameLevel3, 3, L"", TRUE , gShellLevel3HiiHandle, STRING_TOKEN(STR_GET_HELP_VER)); + ShellCommandRegisterCommandName(L"alias", ShellCommandRunAlias , ShellCommandGetManFileNameLevel3, 3, L"", TRUE , gShellLevel3HiiHandle, STRING_TOKEN(STR_GET_HELP_ALIAS)); + ShellCommandRegisterCommandName(L"cls", ShellCommandRunCls , ShellCommandGetManFileNameLevel3, 3, L"", TRUE , gShellLevel3HiiHandle, STRING_TOKEN(STR_GET_HELP_CLS)); + ShellCommandRegisterCommandName(L"echo", ShellCommandRunEcho , ShellCommandGetManFileNameLevel3, 3, L"", FALSE, gShellLevel3HiiHandle, STRING_TOKEN(STR_GET_HELP_ECHO)); + ShellCommandRegisterCommandName(L"pause", ShellCommandRunPause , ShellCommandGetManFileNameLevel3, 3, L"", TRUE , gShellLevel3HiiHandle, STRING_TOKEN(STR_GET_HELP_PAUSE)); + ShellCommandRegisterCommandName(L"getmtc", ShellCommandRunGetMtc , ShellCommandGetManFileNameLevel3, 3, L"", TRUE , gShellLevel3HiiHandle, STRING_TOKEN(STR_GET_HELP_GETMTC)); + ShellCommandRegisterCommandName(L"help", ShellCommandRunHelp , ShellCommandGetManFileNameLevel3, 3, L"", TRUE , gShellLevel3HiiHandle, STRING_TOKEN(STR_GET_HELP_HELP)); + + ShellCommandRegisterAlias(L"type", L"cat"); + + return (EFI_SUCCESS); +} + +/** + Destructor for the library. free any resources. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. +**/ +EFI_STATUS +EFIAPI +ShellLevel3CommandsLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + if (gShellLevel3HiiHandle != NULL) { + HiiRemovePackages(gShellLevel3HiiHandle); + } + return (EFI_SUCCESS); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.h new file mode 100644 index 00000000..c4f07f65 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.h @@ -0,0 +1,155 @@ +/** @file + header file for NULL named library for level 3 shell command functions. + + Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _UEFI_SHELL_LEVEL3_COMMANDS_LIB_H_ +#define _UEFI_SHELL_LEVEL3_COMMANDS_LIB_H_ + +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern EFI_HII_HANDLE gShellLevel3HiiHandle; + +/** + Function for 'type' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunType ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'touch' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunTouch ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'ver' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunVer ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'alias' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunAlias ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'cls' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunCls ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'echo' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunEcho ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'pause' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunPause ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'getmtc' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunGetMtc ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'help' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunHelp ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +#endif + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf new file mode 100644 index 00000000..d959bb4e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf @@ -0,0 +1,70 @@ +## @file +# Provides shell level 3 functions +# Note that the interactive versions of the time, date, and timezone functions are handled in the level 2 library. +# +# (C) Copyright 2013 Hewlett-Packard Development Company, L.P.
+# Copyright (c) 2009-2015, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiShellLevel3CommandsLib + FILE_GUID = 71374B42-85D7-4753-AD17-AA84C3A0EB93 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = ShellLevel3CommandsLibConstructor + DESTRUCTOR = ShellLevel3CommandsLibDestructor + +[Sources.common] +# note that time, timezone, and date are part of the level 2 library + Type.c + Touch.c + Ver.c + UefiShellLevel3CommandsLib.uni + UefiShellLevel3CommandsLib.c + UefiShellLevel3CommandsLib.h + Cls.c + Alias.c + Echo.c + Pause.c + GetMtc.c + Help.c + + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + VBoxPkg/VBoxPkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + ShellCommandLib + ShellLib + UefiLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + PcdLib + HiiLib + FileHandleLib + HandleParsingLib + +[Guids] + gEfiFileInfoGuid ## UNDEFINED + gShellLevel3HiiGuid ## SOMETIMES_CONSUMES ## HII + +[Pcd.common] + gEfiShellPkgTokenSpaceGuid.PcdShellSupportLevel ## CONSUMES + gEfiShellPkgTokenSpaceGuid.PcdShellFileOperationSize ## SOMETIMES_CONSUMES + gEfiShellPkgTokenSpaceGuid.PcdShellSupplier ## SOMETIMES_CONSUMES + +[Protocols] + gEfiShellDynamicCommandProtocolGuid ## SOMETIMES_CONSUMES diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.uni b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.uni new file mode 100644 index 00000000..8ccbb26b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.uni @@ -0,0 +1,539 @@ +// /** +// +// (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+// (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
+// Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// Module Name: +// +// UefiShellLevel3CommandsLib.uni +// +// Abstract: +// +// String definitions for UEFI Shell 2.0 level 3 commands +// +// +// **/ + +/=# + +#langdef en-US "english" + +#string STR_GEN_TOO_MANY #language en-US "%H%s%N: Too many arguments\r\n" +#string STR_GEN_TOO_FEW #language en-US "%H%s%N: Too few arguments\r\n" +#string STR_GEN_PARAM_INV #language en-US "%H%s%N: Invalid argument - '%H%s%N'\r\n" +#string STR_GEN_PROBLEM #language en-US "%H%s%N: Unknown flag - '%H%s%N'\r\n" +#string STR_GEN_NO_VALUE #language en-US "%H%s%N: Missing argument for flag - '%H%s%N'\r\n" +#string STR_GEN_ERR_AD #language en-US "%H%s%N: Access denied.\r\n" +#string STR_GEN_ERR_NOT_FOUND #language en-US "%H%s%N: '%H%s%N' does not exist.\r\n" +#string STR_GEN_ERR_UK #language en-US "%H%s%N: Status: %r\r\n" +#string STR_GEN_PARAM_CON #language en-US "%H%s%N: Parameters conflict\r\n" +#string STR_GEN_PARAM_CONFLICT #language en-US "%H%s%N: Flags conflict with - '%H%s%N' and '%H%s%N'\r\n" +#string STR_GEN_FILE_OPEN_FAIL #language en-US "%H%s%N: Cannot open file - '%H%s%N'\r\n" +#string STR_GEN_FILE_AD #language en-US "%H%s%N: Access file error - '%H%s%N'\r\n" +#string STR_GEN_CRLF #language en-US "\r\n" +#string STR_GEN_NO_CWD #language en-US "%H%s%N: Current directory not specified\r\n" +#string STR_GEN_NO_FILES #language en-US "%H%s%N: No matching files were found\r\n" +#string STR_GEN_DIR_NF #language en-US "%H%s%N: Directory not found - '%H%s%N'\r\n" +#string STR_GEN_FILE_NF #language en-US "%H%s%N: File not found - '%H%s%N'\r\n" +#string STR_GEN_IS_DIR #language en-US "%H%s%N: '%H%s%N' is a directory\r\n" +#string STR_GEN_SFO_HEADER #language en-US "ShellCommand,"%s"\r\n" +#string STR_NO_SCRIPT #language en-US "The command '%H%s%N' is not allowed outside of a script\r\n" + +#string STR_TYP_ERROR #language en-US "%H%s%N: Operation was not successful on '%H%s%N'\r\n" + +#string STR_TOUCH_ERROR #language en-US "%H%s%N: Operation was not successful on '%H%s%N'\r\n" + +#string STR_VER_OUTPUT_SHELL #language en-US "UEFI %s Shell v%d.%d\r\n" +#string STR_VER_OUTPUT_SIMPLE #language en-US "%d.%d\r\n" +#string STR_VER_OUTPUT_UEFI #language en-US "UEFI v%d.%02d (%s, 0x%08x)\r\n" +#string STR_VER_OUTPUT_SUPPLIER #language en-US "%s\r\n" + +#string STR_ECHO_ON #language en-US "Echo is on.\r\n" +#string STR_ECHO_OFF #language en-US "Echo is off.\r\n" + +#string STR_PAUSE_PROMPT #language en-US "Enter 'q' to quit, any other key to continue:\r\n" + +#string STR_HELP_NF #language en-US "No help could be found for command '%B%s%N'.\r\n" +#string STR_HELP_INV #language en-US "The help data for command '%B%s%N' was incorrect format.\r\n" +#string STR_HELP_SC_HEADER #language en-US "Character Description\r\n" + "--------- ---------------------------------------------- \r\n" +#string STR_HELP_SC_DATA #language en-US " Ends a command line.\r\n" + " Ends an argument, if it is not in a quotation.\r\n" + "# Starts a comment.\r\n" + "> Used for output redirection.\r\n" + "< Used for input redirection.\r\n" + "| Used for pipe command support.\r\n" + "% Used to delimit a variable or an argument.\r\n" + "\" Used to delimit a quotation.\r\n" + "^ Prevents the next character from being\r\n" + " interpreted as having special meaning.\r\n" + " Can be used inside quoted strings.\r\n" + "*, ?, [, ] Wildcards to specify multiple similar file names.\r\n" +#string STR_HELP_COMMAND #language en-US "%H%-14s%N- %s\r\n" +#string STR_HELP_FOOTER #language en-US "%N\r\nHelp usage:help [%Hcmd%N|%Hpattern%N|%Hspecial%N] [%H-usage%N] [%H-verbose%N] [%H-section name%N][%H-b%N]\r\n" + +#string STR_HELP_PAGE_COMMAND #language en-US "%N%s\r\n" + +#string STR_ALIAS_OUTPUT #language en-US "%1c %10s:%s\r\n" + +#string STR_GET_MTC_OUTPUT #language en-US "%016Lx\r\n" +#string STR_CLS_OUTPUT_SFO #language en-US "ConOutAttribInfo,"%d","%d","%d"\r\n" + +#string STR_GET_HELP_HELP #language en-US "" +".TH help 0 "Displays help information from the UEFI Shell."\r\n" +".SH NAME\r\n" +"Displays the UEFI Shell command list or verbose command help.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"HELP [cmd | pattern | special] [-usage] [-verbose] [-section sectionname][-b]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -usage - Displays the usage information for the command. The same as\r\n" +" specifying "-section NAME" and "-section SYNOPSIS" \r\n" +" -section - Displays the specified section of the help information.\r\n" +" -b - Displays one page on screen and allows user to continue\r\n" +" to next page\r\n" +" cmd - Specifies a command to display help about.\r\n" +" pattern - Specifies a pattern which describes the commands to be displayed.\r\n" +" special - Displays a list of the special characters used in the shell\r\n" +" command line.\r\n" +" sectionname - Specifies a section name. Supported options are:\r\n" +" - NAME\r\n" +" - SYNOPSIS\r\n" +" - OPTIONS\r\n" +" - DESCRIPTION\r\n" +" - EXAMPLES\r\n" +" - RETURNVALUES\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. The HELP command displays information about one or more shell commands.\r\n" +" 2. If no other options are specified, each command will be displayed along\r\n" +" with a brief description of its function.\r\n" +" 3. If -verbose is specified, then display all help information for the\r\n" +" specified commands.\r\n" +" 4. If -section is specified, only the help section specified will be\r\n" +" displayed.\r\n" +" 5. If -usage is specified, then the command, a brief description\r\n" +" and the usage will be displayed.\r\n" +" 6. The help text is gathered from UCS-2 text files found in the directory\r\n" +" where the shell or shell command executable was located. The files have\r\n" +" the name commandname.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display the list of commands in the UEFI Shell and break after one\r\n" +" screen:\r\n" +" Shell> help -b\r\n" +" \r\n" +" * To display help information of a Shell command - ls:\r\n" +" Shell> help ls\r\n" +" Shell> -? ls\r\n" +" Shell> ls -?\r\n" +" \r\n" +" * To display the list of commands that start with character 'p':\r\n" +" Shell> help p*\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" 0 The help was displayed\r\n" +" 1 No command help was displayed\r\n" + +#string STR_GET_HELP_ALIAS #language en-US "" +".TH alias 0 "Handles aliases in the Shell."\r\n" +".SH NAME\r\n" +"Displays, creates, or deletes UEFI Shell aliases.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"ALIAS [-d|-v] [alias-name] [command-name]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -d - Deletes an alias. Command-name must not be specified.\r\n" +" -v - Makes the alias volatile.\r\n" +" alias-name - Specifies an alias name.\r\n" +" command-name - Specifies an original command's name or path.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command displays, creates, or deletes aliases in the UEFI Shell\r\n" +" environment.\r\n" +" 2. An alias provides a new name for an existing UEFI Shell\r\n" +" command or UEFI application. Once the alias is created, it can be used\r\n" +" to run the command or launch the UEFI application.\r\n" +" 3. There are some aliases that are predefined in the UEFI Shell environment.\r\n" +" These aliases provide the MS-DOS and UNIX equivalent names for the file\r\n" +" manipulation commands.\r\n" +" 4. Aliases will be retained even after exiting the shell unless the -v option\r\n" +" is specified. If -v is specified then the alias will not be valid after\r\n" +" leaving the shell.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display all aliases in the UEFI Shell environment:\r\n" +" Shell> alias\r\n" +" \r\n" +" * To create an alias in the UEFI Shell environment:\r\n" +" Shell> alias shutdown "reset -s" \r\n" +" \r\n" +" * To delete an alias in the UEFI Shell environment:\r\n" +" Shell> alias -d shutdown\r\n" +" \r\n" +" * To add a volatile alias in the current UEFI environment, which has a star *\r\n" +" at the line head. This volatile alias will disappear at next boot.\r\n" +" Shell> alias -v fs0 floppy\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_INVALID_PARAMETER One of the passed-in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" +" SHELL_OUT_OF_RESOURCES A request to set a variable in a non-volatile\r\n" +" fashion could not be completed. The resulting\r\n" +" non-volatile request has been converted into\r\n" +" a volatile request.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" + +#string STR_GET_HELP_CLS #language en-US "" +".TH cls 0 "clear screen"\r\n" +".SH NAME\r\n" +"Clears the console output and optionally changes the background and foreground color.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"CLS [background] [foreground] | [-sfo]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" background - Sets a new background color:\r\n" +" 0 - Black\r\n" +" 1 - Blue\r\n" +" 2 - Green\r\n" +" 3 - Cyan\r\n" +" 4 - Red\r\n" +" 5 - Magenta\r\n" +" 6 - Yellow\r\n" +" 7 - Light gray\r\n" +" foreground - Sets a new foreground color:\r\n" +" 0 - Black\r\n" +" 1 - Blue\r\n" +" 2 - Green\r\n" +" 3 - Cyan\r\n" +" 4 - Red\r\n" +" 5 - Magenta\r\n" +" 6 - Yellow\r\n" +" 7 - Light gray\r\n" +" 8 - Dark gray\r\n" +" 9 - Light blue\r\n" +" 10 - Light green\r\n" +" 11 - Light cyan\r\n" +" 12 - Light red\r\n" +" 13 - Light magenta\r\n" +" 14 - Yellow\r\n" +" 15 - White\r\n" +" -sfo - Displays current console color settings in Standard Format\r\n" +" Output.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command clears the standard output device with an optional\r\n" +" background and foreground color attribute.\r\n" +" 2. If background color is not specified, or if background and foreground\r\n" +" colors are not specified, then the colors do not change.\r\n" +" 3. When -sfo flag is used, console output is not cleared and instead it\r\n" +" displays current console foreground and background attribute settings.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To clear standard output without changing the background or foreground\r\n" +" color:\r\n" +" fs0:\> cls\r\n" +" \r\n" +" * To clear standard output and change the background color to cyan:\r\n" +" fs0:\> cls 3\r\n" +" \r\n" +" * To clear standard output and change the background to black and foreground\r\n" +" to white:\r\n" +" fs0:\> cls 0 15\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_INVALID_PARAMETER One of the passed-in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_NOT_FOUND The requested file was not found.\r\n" + +#string STR_GET_HELP_ECHO #language en-US "" +".TH echo 0 "display text or control text output"\r\n" +".SH NAME\r\n" +"Controls script file command echoing or displays a message.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"ECHO [-on|-off]\r\n" +"ECHO [message]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -on - Enables display when reading commands from script files.\r\n" +" -off - Disables display when reading commands from script files.\r\n" +" message - Specifies a message to display.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. The first form of this command controls whether script commands are\r\n" +" displayed as they are read from the script file. If no argument is given,\r\n" +" the current "on" or "off" status is displayed.\r\n" +" 2. The second form prints the given message to the display.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display a message string of 'Hello World':\r\n" +" fs0:\> echo Hello World\r\n" +" \r\n" +" * To turn command echoing on:\r\n" +" fs0:\> echo -on\r\n" +" \r\n" +" * To execute HelloWorld.nsh, and display when reading lines from the script\r\n" +" file:\r\n" +" fs0:\> HelloWorld.nsh\r\n" +" +HelloWorld.nsh> echo Hello World\r\n" +" \r\n" +" * To turn command echoing off:\r\n" +" fs0:\> echo -off\r\n" +" \r\n" +" * To display the current echo setting:\r\n" +" fs0:\> echo\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" + +#string STR_GET_HELP_GETMTC #language en-US "" +".TH getmtc 0 "gets the MTC count"\r\n" +".SH NAME\r\n" +"Gets the MTC from BootServices and displays it.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"GETMTC\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command displays the current monotonic counter value. The lower 32\r\n" +" bits increment every time this command is executed. Every time the system\r\n" +" is reset, the upper 32 bits will be incremented, and the lower 32 bits\r\n" +" will be reset to 0.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display the current monotonic counter value:\r\n" +" fs0:\> getmtc\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_DEVICE_ERROR The underlying device was not working correctly.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" + +#string STR_GET_HELP_PAUSE #language en-US "" +".TH pause 0 "pauses scripts"\r\n" +".SH NAME\r\n" +"Pauses a script and waits for an operator to press a key.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"PAUSE [-q]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -q - Does not display a test output prompt.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. The PAUSE command prints a message to the display, then suspends script\r\n" +" file execution, and waits for keyboard input. Pressing any key resumes\r\n" +" execution, except for q or Q. If either q or Q is pressed, script\r\n" +" processing terminates; otherwise, execution continues with the next line\r\n" +" after the pause command.\r\n" +" 2. The PAUSE command is available only in scripts. Switch -q can hide the\r\n" +" message and it's optional.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * Following script is a sample of 'pause' command:\r\n" +" fs0:\> type pause.nsh\r\n" +" #\r\n" +" # Example script for 'pause' command\r\n" +" #\r\n" +" echo pause.nsh begin..\r\n" +" date\r\n" +" time\r\n" +" pause\r\n" +" echo pause.nsh done.\r\n" +" \r\n" +" * To execute the script with echo on:\r\n" +" fs0:\> pause.nsh\r\n" +" +pause.nsh> echo pause.nsh begin..\r\n" +" pause.nsh begin..\r\n" +" +pause.nsh> date\r\n" +" 06/19/2001\r\n" +" +pause.nsh> time\r\n" +" 00:51:45\r\n" +" +pause.nsh> pause\r\n" +" Enter 'q' to quit, or any other key to continue:\r\n" +" +pause.nsh> echo pause.nsh done.\r\n" +" pause.nsh done.\r\n" +" \r\n" +" * To execute the script with echo off:\r\n" +" fs0:\> echo -off\r\n" +" fs0:\> pause.nsh\r\n" +" pause.nsh begin..\r\n" +" 06/19/2001\r\n" +" 00:52:50\r\n" +" Enter 'q' to quit, or any other key to continue: q\r\n" +" fs0:\>\r\n" + +#string STR_GET_HELP_TOUCH #language en-US "" +".TH touch 0 "Touch a file to update a directory"\r\n" +".SH NAME\r\n" +"Updates the filename timestamp with the current system date and time.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"TOUCH [-r] file [file ...]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -r - Sets the update as recurse into subdirectories.\r\n" +" file - Specifies the name or pattern of the file or directory. There can be multiple \r\n" +" files on the command-line.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command updates to the current time and date the time and date on\r\n" +" the file that is specified by the file parameter.\r\n" +" 2. If multiple files are specified on the command line, it will continue\r\n" +" processing. It will touch the files one by one and errors will be\r\n" +" ignored.\r\n" +" 3. TOUCH cannot change the time and date of read-only files and directories.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To update the timestamp of a specific file:\r\n" +" fs0:\> touch for.nsh\r\n" +" \r\n" +" * To touch a directory recursively:\r\n" +" fs0:\> touch -r efi1.1\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_NOT_FOUND The target file or set of files were not found.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_WRITE_PROTECTED The media was write-protected or the file had a\r\n" +" read-only attribute associated with it.\r\n" + +#string STR_GET_HELP_TYPE #language en-US "" +".TH type 0 "print a file to StdOut"\r\n" +".SH NAME\r\n" +"Sends the contents of a file to the standard output device.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"TYPE [-a|-u] file [file...]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -a - Displays the file as if it is encoded as 8-bit ASCII\r\n" +" -u - Displays the file as if it were encoded as UCS-2 Unicode.\r\n" +" file - Specifies the name of the file to display.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command sends the contents of a file to the standard output device.\r\n" +" If no options are used, then the command attempts to automatically detect\r\n" +" the file type. If it fails, then UCS-2 is presumed.\r\n" +" 2. If the -a option is specified, the file is sent to the standard output\r\n" +" device as a stream of ASCII characters.\r\n" +" 3. If the -u option is specified, the file is sent to the standard output\r\n" +" device as a stream of Unicode (UCS-2) characters.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display a file in UCS-2 format:\r\n" +" fs0:\> type -u pause.nsh\r\n" +" \r\n" +" * To display a file in ASCII format:\r\n" +" fs0:\> type -a pause.nsh\r\n" +" \r\n" +" * To display multiple files:\r\n" +" fs0:\> type test.*\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_INVALID_PARAMETER One of the passed in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" +" SHELL_SECURITY_VIOLATION This function was not performed due to a security\r\n" +" violation.\r\n" +" SHELL_NOT_FOUND The target file or set of files were not found.\r\n" + +#string STR_GET_HELP_VER #language en-US "" +".TH ver 0 "prints out version info"\r\n" +".SH NAME\r\n" +"Displays UEFI Firmware version information.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"VER [-s|-terse]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -s - Displays only the UEFI Shell version.\r\n" +" -terse - Displays only the first part of the data.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command displays the version information for this UEFI Firmware, or\r\n" +" the version information for the UEFI Shell itself. The information is\r\n" +" retrieved through the UEFI System Table or the Shell image.\r\n" +" \r\n" +" 2. Standard format for ver output as shown below with a sample:\r\n" +" UEFI Shell v\r\n" +" shell-supplier-specific-data\r\n" +" UEFI v (, 0x )\r\n" +" #\r\n" +" # Sample \r\n" +" #\r\n" +" UEFI Basic Shell v2.0\r\n" +" Copyright 2008 by Intel(R) Corporation.\r\n" +" UEFI v2.31 (Intel(R) Corporation., 0x00010100)\r\n" +" \r\n" +" 3. UEFI version tag information:\r\n" +" \r\n" +" 0 = Minimal\r\n" +" 1 = Scripting\r\n" +" 2 = Basic\r\n" +" 3 = Interactive\r\n" +" \r\n" +" Comes from the Shell specification upon which the Shell\r\n" +" implementation is based.\r\n" +" \r\n" +" Build, copyright, etc.\r\n" +" \r\n" +" Comes from the UEFI specification upon which the firmware\r\n" +" implementation is based\r\n" +" \r\n" +" Indicates Vendor Name\r\n" +" \r\n" +" Indicates Vendor's firmware version\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To display UEFI Firmware version information:\r\n" +" fs0:\> ver\r\n" +" \r\n" +" * To display UEFI Shell version information only:\r\n" +" Shell> ver -s\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Ver.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Ver.c new file mode 100644 index 00000000..4a07b1eb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLevel3CommandsLib/Ver.c @@ -0,0 +1,158 @@ +/** @file + Main file for Ver shell level 3 function. + + (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+ (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLevel3CommandsLib.h" + +#include +#ifdef VBOX +# include +#endif + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-s", TypeFlag}, + {L"-terse", TypeFlag}, + {L"-t", TypeFlag}, + {L"-_pa", TypeFlag}, +#ifdef VBOX + {L"-vbox", TypeFlag}, +#endif + {NULL, TypeMax} + }; + +/** + Function for 'ver' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunVer ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + UINT8 Level; + + Level = PcdGet8(PcdShellSupportLevel); + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, L"ver", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } + if (ShellCommandLineGetRawValue(Package, 1) != NULL) { + // + // we have too many parameters + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel3HiiHandle, L"ver"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + if (ShellCommandLineGetFlag(Package, L"-s")) { + if (ShellCommandLineGetFlag(Package, L"-terse") || ShellCommandLineGetFlag(Package, L"-t")){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CONFLICT), gShellLevel3HiiHandle, L"ver", L"-t or -terse", L"-s"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ShellPrintHiiEx ( + 0, + gST->ConOut->Mode->CursorRow, + NULL, + STRING_TOKEN (STR_VER_OUTPUT_SIMPLE), + gShellLevel3HiiHandle, + gEfiShellProtocol->MajorVersion, + gEfiShellProtocol->MinorVersion + ); + } + } else { + ShellPrintHiiEx ( + 0, + gST->ConOut->Mode->CursorRow, + NULL, + STRING_TOKEN (STR_VER_OUTPUT_SHELL), + gShellLevel3HiiHandle, + SupportLevel[Level], + gEfiShellProtocol->MajorVersion, + gEfiShellProtocol->MinorVersion + ); + if (!ShellCommandLineGetFlag(Package, L"-terse") && !ShellCommandLineGetFlag(Package, L"-t")){ + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_VER_OUTPUT_SUPPLIER), + gShellLevel3HiiHandle, + (CHAR16 *) PcdGetPtr (PcdShellSupplier) + ); + + + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_VER_OUTPUT_UEFI), + gShellLevel3HiiHandle, + (gST->Hdr.Revision&0xffff0000)>>16, + (gST->Hdr.Revision&0x0000ffff), + gST->FirmwareVendor, + gST->FirmwareRevision + ); + } + } + // + // implementation specific support for displaying processor architecture + // + if (ShellCommandLineGetFlag(Package, L"-_pa")) { + ShellPrintEx(-1, -1, L"%d\r\n", sizeof(UINTN)==sizeof(UINT64)?64:32); + } +#ifdef VBOX + if (ShellCommandLineGetFlag(Package, L"-vbox")) { + ShellPrintEx(-1, -1, L"Oracle(r) VirtualBox(tm) %d.%d.%d r%d\r\n", VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_REV); + } +#endif + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + } + + return (ShellStatus); +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLib/UefiShellLib.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLib/UefiShellLib.c new file mode 100644 index 00000000..b3af965f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLib/UefiShellLib.c @@ -0,0 +1,4392 @@ +/** @file + Provides interface to shell functionality for shell commands and applications. + + (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+ Copyright 2016-2018 Dell Technologies.
+ Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellLib.h" +#include +#include + +// +// globals... +// +SHELL_PARAM_ITEM EmptyParamList[] = { + {NULL, TypeMax} + }; +SHELL_PARAM_ITEM SfoParamList[] = { + {L"-sfo", TypeFlag}, + {NULL, TypeMax} + }; +EFI_SHELL_ENVIRONMENT2 *mEfiShellEnvironment2; +EFI_SHELL_INTERFACE *mEfiShellInterface; +EFI_SHELL_PROTOCOL *gEfiShellProtocol; +EFI_SHELL_PARAMETERS_PROTOCOL *gEfiShellParametersProtocol; +EFI_HANDLE mEfiShellEnvironment2Handle; +FILE_HANDLE_FUNCTION_MAP FileFunctionMap; +EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollationProtocol; + +/** + Return a clean, fully-qualified version of an input path. If the return value + is non-NULL the caller must free the memory when it is no longer needed. + + If asserts are disabled, and if the input parameter is NULL, NULL is returned. + + If there is not enough memory available to create the fully-qualified path or + a copy of the input path, NULL is returned. + + If there is no working directory, a clean copy of Path is returned. + + Otherwise, the current file system or working directory (as appropriate) is + prepended to Path and the resulting path is cleaned and returned. + + NOTE: If the input path is an empty string, then the current working directory + (if it exists) is returned. In other words, an empty input path is treated + exactly the same as ".". + + @param[in] Path A pointer to some file or directory path. + + @retval NULL The input path is NULL or out of memory. + + @retval non-NULL A pointer to a clean, fully-qualified version of Path. + If there is no working directory, then a pointer to a + clean, but not necessarily fully-qualified version of + Path. The caller must free this memory when it is no + longer needed. +**/ +CHAR16* +EFIAPI +FullyQualifyPath( + IN CONST CHAR16 *Path + ) +{ + CONST CHAR16 *WorkingPath; + CONST CHAR16 *InputPath; + CHAR16 *CharPtr; + CHAR16 *InputFileSystem; + UINTN FileSystemCharCount; + CHAR16 *FullyQualifiedPath; + UINTN Size; + + FullyQualifiedPath = NULL; + + ASSERT(Path != NULL); + // + // Handle erroneous input when asserts are disabled. + // + if (Path == NULL) { + return NULL; + } + // + // In paths that contain ":", like fs0:dir/file.ext and fs2:\fqpath\file.ext, + // we have to consider the file system part separately from the "path" part. + // If there is a file system in the path, we have to get the current working + // directory for that file system. Then we need to use the part of the path + // following the ":". If a path does not contain ":", we use it as given. + // + InputPath = StrStr(Path, L":"); + if (InputPath != NULL) { + InputPath++; + FileSystemCharCount = ((UINTN)InputPath - (UINTN)Path + sizeof(CHAR16)) / sizeof(CHAR16); + InputFileSystem = AllocateCopyPool(FileSystemCharCount * sizeof(CHAR16), Path); + if (InputFileSystem != NULL) { + InputFileSystem[FileSystemCharCount - 1] = CHAR_NULL; + } + WorkingPath = ShellGetCurrentDir(InputFileSystem); + SHELL_FREE_NON_NULL(InputFileSystem); + } else { + InputPath = Path; + WorkingPath = ShellGetEnvironmentVariable(L"cwd"); + } + + if (WorkingPath == NULL) { + // + // With no working directory, all we can do is copy and clean the input path. + // + FullyQualifiedPath = AllocateCopyPool(StrSize(Path), Path); + } else { + // + // Allocate space for both strings plus one more character. + // + Size = StrSize(WorkingPath) + StrSize(InputPath); + FullyQualifiedPath = AllocateZeroPool(Size); + if (FullyQualifiedPath == NULL) { + // + // Try to copy and clean just the input. No harm if not enough memory. + // + FullyQualifiedPath = AllocateCopyPool(StrSize(Path), Path); + } else { + if (*InputPath == L'\\' || *InputPath == L'/') { + // + // Absolute path: start with the current working directory, then + // truncate the new path after the file system part. + // + StrCpyS(FullyQualifiedPath, Size/sizeof(CHAR16), WorkingPath); + CharPtr = StrStr(FullyQualifiedPath, L":"); + if (CharPtr != NULL) { + *(CharPtr + 1) = CHAR_NULL; + } + } else { + // + // Relative path: start with the working directory and append "\". + // + StrCpyS(FullyQualifiedPath, Size/sizeof(CHAR16), WorkingPath); + StrCatS(FullyQualifiedPath, Size/sizeof(CHAR16), L"\\"); + } + // + // Now append the absolute or relative path. + // + StrCatS(FullyQualifiedPath, Size/sizeof(CHAR16), InputPath); + } + } + + PathCleanUpDirectories(FullyQualifiedPath); + + return FullyQualifiedPath; +} + +/** + Check if a Unicode character is a hexadecimal character. + + This internal function checks if a Unicode character is a + numeric character. The valid hexadecimal characters are + L'0' to L'9', L'a' to L'f', or L'A' to L'F'. + + @param Char The character to check against. + + @retval TRUE If the Char is a hexadecmial character. + @retval FALSE If the Char is not a hexadecmial character. + +**/ +BOOLEAN +EFIAPI +ShellIsHexaDecimalDigitCharacter ( + IN CHAR16 Char + ) +{ + return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f')); +} + +/** + Check if a Unicode character is a decimal character. + + This internal function checks if a Unicode character is a + decimal character. The valid characters are + L'0' to L'9'. + + + @param Char The character to check against. + + @retval TRUE If the Char is a hexadecmial character. + @retval FALSE If the Char is not a hexadecmial character. + +**/ +BOOLEAN +EFIAPI +ShellIsDecimalDigitCharacter ( + IN CHAR16 Char + ) +{ + return (BOOLEAN) (Char >= L'0' && Char <= L'9'); +} + +/** + Helper function to find ShellEnvironment2 for constructor. + + @param[in] ImageHandle A copy of the calling image's handle. + + @retval EFI_OUT_OF_RESOURCES Memory allocation failed. +**/ +EFI_STATUS +ShellFindSE2 ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + EFI_HANDLE *Buffer; + UINTN BufferSize; + UINTN HandleIndex; + + BufferSize = 0; + Buffer = NULL; + Status = gBS->OpenProtocol(ImageHandle, + &gEfiShellEnvironment2Guid, + (VOID **)&mEfiShellEnvironment2, + ImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + // + // look for the mEfiShellEnvironment2 protocol at a higher level + // + if (EFI_ERROR (Status) || !(CompareGuid (&mEfiShellEnvironment2->SESGuid, &gEfiShellEnvironment2ExtGuid))){ + // + // figure out how big of a buffer we need. + // + Status = gBS->LocateHandle (ByProtocol, + &gEfiShellEnvironment2Guid, + NULL, // ignored for ByProtocol + &BufferSize, + Buffer + ); + // + // maybe it's not there??? + // + if (Status == EFI_BUFFER_TOO_SMALL) { + Buffer = (EFI_HANDLE*)AllocateZeroPool(BufferSize); + if (Buffer == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + Status = gBS->LocateHandle (ByProtocol, + &gEfiShellEnvironment2Guid, + NULL, // ignored for ByProtocol + &BufferSize, + Buffer + ); + } + if (!EFI_ERROR (Status) && Buffer != NULL) { + // + // now parse the list of returned handles + // + Status = EFI_NOT_FOUND; + for (HandleIndex = 0; HandleIndex < (BufferSize/sizeof(Buffer[0])); HandleIndex++) { + Status = gBS->OpenProtocol(Buffer[HandleIndex], + &gEfiShellEnvironment2Guid, + (VOID **)&mEfiShellEnvironment2, + ImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (CompareGuid (&mEfiShellEnvironment2->SESGuid, &gEfiShellEnvironment2ExtGuid)) { + mEfiShellEnvironment2Handle = Buffer[HandleIndex]; + Status = EFI_SUCCESS; + break; + } + } + } + } + if (Buffer != NULL) { + FreePool (Buffer); + } + return (Status); +} + +/** + Function to do most of the work of the constructor. Allows for calling + multiple times without complete re-initialization. + + @param[in] ImageHandle A copy of the ImageHandle. + @param[in] SystemTable A pointer to the SystemTable for the application. + + @retval EFI_SUCCESS The operationw as successful. +**/ +EFI_STATUS +ShellLibConstructorWorker ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + if (gEfiShellProtocol == NULL) { + // + // UEFI 2.0 shell interfaces (used preferentially) + // + Status = gBS->OpenProtocol ( + ImageHandle, + &gEfiShellProtocolGuid, + (VOID **)&gEfiShellProtocol, + ImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + // + // Search for the shell protocol + // + Status = gBS->LocateProtocol ( + &gEfiShellProtocolGuid, + NULL, + (VOID **)&gEfiShellProtocol + ); + if (EFI_ERROR (Status)) { + gEfiShellProtocol = NULL; + } + } + } + + if (gEfiShellParametersProtocol == NULL) { + Status = gBS->OpenProtocol ( + ImageHandle, + &gEfiShellParametersProtocolGuid, + (VOID **)&gEfiShellParametersProtocol, + ImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + gEfiShellParametersProtocol = NULL; + } + } + + if (gEfiShellProtocol == NULL) { + // + // Moved to seperate function due to complexity + // + Status = ShellFindSE2(ImageHandle); + + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Status: 0x%08x\r\n", Status)); + mEfiShellEnvironment2 = NULL; + } + Status = gBS->OpenProtocol(ImageHandle, + &gEfiShellInterfaceGuid, + (VOID **)&mEfiShellInterface, + ImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR(Status)) { + mEfiShellInterface = NULL; + } + } + + // + // Getting either EDK Shell's ShellEnvironment2 and ShellInterface protocol + // or UEFI Shell's Shell protocol. + // When ShellLib is linked to a driver producing DynamicCommand protocol, + // ShellParameters protocol is set by DynamicCommand.Handler(). + // + if ((mEfiShellEnvironment2 != NULL && mEfiShellInterface != NULL) || + (gEfiShellProtocol != NULL) + ) { + if (gEfiShellProtocol != NULL) { + FileFunctionMap.GetFileInfo = gEfiShellProtocol->GetFileInfo; + FileFunctionMap.SetFileInfo = gEfiShellProtocol->SetFileInfo; + FileFunctionMap.ReadFile = gEfiShellProtocol->ReadFile; + FileFunctionMap.WriteFile = gEfiShellProtocol->WriteFile; + FileFunctionMap.CloseFile = gEfiShellProtocol->CloseFile; + FileFunctionMap.DeleteFile = gEfiShellProtocol->DeleteFile; + FileFunctionMap.GetFilePosition = gEfiShellProtocol->GetFilePosition; + FileFunctionMap.SetFilePosition = gEfiShellProtocol->SetFilePosition; + FileFunctionMap.FlushFile = gEfiShellProtocol->FlushFile; + FileFunctionMap.GetFileSize = gEfiShellProtocol->GetFileSize; + } else { + FileFunctionMap.GetFileInfo = (EFI_SHELL_GET_FILE_INFO)FileHandleGetInfo; + FileFunctionMap.SetFileInfo = (EFI_SHELL_SET_FILE_INFO)FileHandleSetInfo; + FileFunctionMap.ReadFile = (EFI_SHELL_READ_FILE)FileHandleRead; + FileFunctionMap.WriteFile = (EFI_SHELL_WRITE_FILE)FileHandleWrite; + FileFunctionMap.CloseFile = (EFI_SHELL_CLOSE_FILE)FileHandleClose; + FileFunctionMap.DeleteFile = (EFI_SHELL_DELETE_FILE)FileHandleDelete; + FileFunctionMap.GetFilePosition = (EFI_SHELL_GET_FILE_POSITION)FileHandleGetPosition; + FileFunctionMap.SetFilePosition = (EFI_SHELL_SET_FILE_POSITION)FileHandleSetPosition; + FileFunctionMap.FlushFile = (EFI_SHELL_FLUSH_FILE)FileHandleFlush; + FileFunctionMap.GetFileSize = (EFI_SHELL_GET_FILE_SIZE)FileHandleGetSize; + } + return (EFI_SUCCESS); + } + return (EFI_NOT_FOUND); +} +/** + Constructor for the Shell library. + + Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell. + + @param ImageHandle the image handle of the process + @param SystemTable the EFI System Table pointer + + @retval EFI_SUCCESS the initialization was complete sucessfully + @return others an error ocurred during initialization +**/ +EFI_STATUS +EFIAPI +ShellLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + mEfiShellEnvironment2 = NULL; + gEfiShellProtocol = NULL; + gEfiShellParametersProtocol = NULL; + mEfiShellInterface = NULL; + mEfiShellEnvironment2Handle = NULL; + mUnicodeCollationProtocol = NULL; + + // + // verify that auto initialize is not set false + // + if (PcdGetBool(PcdShellLibAutoInitialize) == 0) { + return (EFI_SUCCESS); + } + + return (ShellLibConstructorWorker(ImageHandle, SystemTable)); +} + +/** + Destructor for the library. free any resources. + + @param[in] ImageHandle A copy of the ImageHandle. + @param[in] SystemTable A pointer to the SystemTable for the application. + + @retval EFI_SUCCESS The operation was successful. + @return An error from the CloseProtocol function. +**/ +EFI_STATUS +EFIAPI +ShellLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + if (mEfiShellEnvironment2 != NULL) { + Status = gBS->CloseProtocol(mEfiShellEnvironment2Handle==NULL?ImageHandle:mEfiShellEnvironment2Handle, + &gEfiShellEnvironment2Guid, + ImageHandle, + NULL); + if (!EFI_ERROR (Status)) { + mEfiShellEnvironment2 = NULL; + mEfiShellEnvironment2Handle = NULL; + } + } + if (mEfiShellInterface != NULL) { + Status = gBS->CloseProtocol(ImageHandle, + &gEfiShellInterfaceGuid, + ImageHandle, + NULL); + if (!EFI_ERROR (Status)) { + mEfiShellInterface = NULL; + } + } + if (gEfiShellProtocol != NULL) { + Status = gBS->CloseProtocol(ImageHandle, + &gEfiShellProtocolGuid, + ImageHandle, + NULL); + if (!EFI_ERROR (Status)) { + gEfiShellProtocol = NULL; + } + } + if (gEfiShellParametersProtocol != NULL) { + Status = gBS->CloseProtocol(ImageHandle, + &gEfiShellParametersProtocolGuid, + ImageHandle, + NULL); + if (!EFI_ERROR (Status)) { + gEfiShellParametersProtocol = NULL; + } + } + + return (EFI_SUCCESS); +} + +/** + This function causes the shell library to initialize itself. If the shell library + is already initialized it will de-initialize all the current protocol poitners and + re-populate them again. + + When the library is used with PcdShellLibAutoInitialize set to true this function + will return EFI_SUCCESS and perform no actions. + + This function is intended for internal access for shell commands only. + + @retval EFI_SUCCESS the initialization was complete sucessfully + +**/ +EFI_STATUS +EFIAPI +ShellInitialize ( + VOID + ) +{ + EFI_STATUS Status; + + // + // if auto initialize is not false then skip + // + if (PcdGetBool(PcdShellLibAutoInitialize) != 0) { + return (EFI_SUCCESS); + } + + // + // deinit the current stuff + // + Status = ShellLibDestructor (gImageHandle, gST); + ASSERT_EFI_ERROR (Status); + + // + // init the new stuff + // + return (ShellLibConstructorWorker(gImageHandle, gST)); +} + +/** + This function will retrieve the information about the file for the handle + specified and store it in allocated pool memory. + + This function allocates a buffer to store the file's information. It is the + caller's responsibility to free the buffer + + @param FileHandle The file handle of the file for which information is + being requested. + + @retval NULL information could not be retrieved. + + @return the information about the file +**/ +EFI_FILE_INFO* +EFIAPI +ShellGetFileInfo ( + IN SHELL_FILE_HANDLE FileHandle + ) +{ + return (FileFunctionMap.GetFileInfo(FileHandle)); +} + +/** + This function sets the information about the file for the opened handle + specified. + + @param[in] FileHandle The file handle of the file for which information + is being set. + + @param[in] FileInfo The information to set. + + @retval EFI_SUCCESS The information was set. + @retval EFI_INVALID_PARAMETER A parameter was out of range or invalid. + @retval EFI_UNSUPPORTED The FileHandle does not support FileInfo. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The file or medium is write protected. + @retval EFI_ACCESS_DENIED The file was opened read only. + @retval EFI_VOLUME_FULL The volume is full. +**/ +EFI_STATUS +EFIAPI +ShellSetFileInfo ( + IN SHELL_FILE_HANDLE FileHandle, + IN EFI_FILE_INFO *FileInfo + ) +{ + return (FileFunctionMap.SetFileInfo(FileHandle, FileInfo)); +} + + /** + This function will open a file or directory referenced by DevicePath. + + This function opens a file with the open mode according to the file path. The + Attributes is valid only for EFI_FILE_MODE_CREATE. + + @param FilePath on input the device path to the file. On output + the remaining device path. + @param FileHandle pointer to the file handle. + @param OpenMode the mode to open the file with. + @param Attributes the file's file attributes. + + @retval EFI_SUCCESS The information was set. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + @retval EFI_UNSUPPORTED Could not open the file path. + @retval EFI_NOT_FOUND The specified file could not be found on the + device or the file system could not be found on + the device. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_MEDIA_CHANGED The device has a different medium in it or the + medium is no longer supported. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The file or medium is write protected. + @retval EFI_ACCESS_DENIED The file was opened read only. + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the + file. + @retval EFI_VOLUME_FULL The volume is full. +**/ +EFI_STATUS +EFIAPI +ShellOpenFileByDevicePath( + IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, + OUT SHELL_FILE_HANDLE *FileHandle, + IN UINT64 OpenMode, + IN UINT64 Attributes + ) +{ + CHAR16 *FileName; + EFI_STATUS Status; + EFI_FILE_PROTOCOL *File; + + if (FilePath == NULL || FileHandle == NULL) { + return (EFI_INVALID_PARAMETER); + } + + // + // which shell interface should we use + // + if (gEfiShellProtocol != NULL) { + // + // use UEFI Shell 2.0 method. + // + FileName = gEfiShellProtocol->GetFilePathFromDevicePath(*FilePath); + if (FileName == NULL) { + return (EFI_INVALID_PARAMETER); + } + Status = ShellOpenFileByName(FileName, FileHandle, OpenMode, Attributes); + FreePool(FileName); + return (Status); + } + + + // + // use old shell method. + // + Status = EfiOpenFileByDevicePath (FilePath, &File, OpenMode, Attributes); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // This is a weak spot since if the undefined SHELL_FILE_HANDLE format changes this must change also! + // + *FileHandle = (VOID*)File; + return (EFI_SUCCESS); +} + +/** + This function will open a file or directory referenced by filename. + + If return is EFI_SUCCESS, the Filehandle is the opened file's handle; + otherwise, the Filehandle is NULL. The Attributes is valid only for + EFI_FILE_MODE_CREATE. + + if FileName is NULL then ASSERT() + + @param FileName pointer to file name + @param FileHandle pointer to the file handle. + @param OpenMode the mode to open the file with. + @param Attributes the file's file attributes. + + @retval EFI_SUCCESS The information was set. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + @retval EFI_UNSUPPORTED Could not open the file path. + @retval EFI_NOT_FOUND The specified file could not be found on the + device or the file system could not be found + on the device. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_MEDIA_CHANGED The device has a different medium in it or the + medium is no longer supported. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The file or medium is write protected. + @retval EFI_ACCESS_DENIED The file was opened read only. + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the + file. + @retval EFI_VOLUME_FULL The volume is full. +**/ +EFI_STATUS +EFIAPI +ShellOpenFileByName( + IN CONST CHAR16 *FileName, + OUT SHELL_FILE_HANDLE *FileHandle, + IN UINT64 OpenMode, + IN UINT64 Attributes + ) +{ + EFI_DEVICE_PATH_PROTOCOL *FilePath; + EFI_STATUS Status; + EFI_FILE_INFO *FileInfo; + CHAR16 *FileNameCopy; + EFI_STATUS Status2; + + // + // ASSERT if FileName is NULL + // + ASSERT(FileName != NULL); + + if (FileName == NULL) { + return (EFI_INVALID_PARAMETER); + } + + if (gEfiShellProtocol != NULL) { + if ((OpenMode & EFI_FILE_MODE_CREATE) == EFI_FILE_MODE_CREATE) { + + // + // Create only a directory + // + if ((Attributes & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY) { + return ShellCreateDirectory(FileName, FileHandle); + } + + // + // Create the directory to create the file in + // + FileNameCopy = AllocateCopyPool (StrSize (FileName), FileName); + if (FileNameCopy == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + PathCleanUpDirectories (FileNameCopy); + if (PathRemoveLastItem (FileNameCopy)) { + if (!EFI_ERROR(ShellCreateDirectory (FileNameCopy, FileHandle))) { + ShellCloseFile (FileHandle); + } + } + SHELL_FREE_NON_NULL (FileNameCopy); + } + + // + // Use UEFI Shell 2.0 method to create the file + // + Status = gEfiShellProtocol->OpenFileByName(FileName, + FileHandle, + OpenMode); + if (EFI_ERROR(Status)) { + return Status; + } + + if (mUnicodeCollationProtocol == NULL) { + Status = gBS->LocateProtocol (&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID**)&mUnicodeCollationProtocol); + if (EFI_ERROR (Status)) { + gEfiShellProtocol->CloseFile (*FileHandle); + return Status; + } + } + + if ((mUnicodeCollationProtocol->StriColl (mUnicodeCollationProtocol, (CHAR16*)FileName, L"NUL") != 0) && + (mUnicodeCollationProtocol->StriColl (mUnicodeCollationProtocol, (CHAR16*)FileName, L"NULL") != 0) && + !EFI_ERROR(Status) && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)){ + FileInfo = FileFunctionMap.GetFileInfo(*FileHandle); + ASSERT(FileInfo != NULL); + FileInfo->Attribute = Attributes; + Status2 = FileFunctionMap.SetFileInfo(*FileHandle, FileInfo); + FreePool(FileInfo); + if (EFI_ERROR (Status2)) { + gEfiShellProtocol->CloseFile(*FileHandle); + } + Status = Status2; + } + return (Status); + } + // + // Using EFI Shell version + // this means convert name to path and call that function + // since this will use EFI method again that will open it. + // + ASSERT(mEfiShellEnvironment2 != NULL); + FilePath = mEfiShellEnvironment2->NameToPath ((CHAR16*)FileName); + if (FilePath != NULL) { + return (ShellOpenFileByDevicePath(&FilePath, + FileHandle, + OpenMode, + Attributes)); + } + return (EFI_DEVICE_ERROR); +} +/** + This function create a directory + + If return is EFI_SUCCESS, the Filehandle is the opened directory's handle; + otherwise, the Filehandle is NULL. If the directory already existed, this + function opens the existing directory. + + @param DirectoryName pointer to directory name + @param FileHandle pointer to the file handle. + + @retval EFI_SUCCESS The information was set. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + @retval EFI_UNSUPPORTED Could not open the file path. + @retval EFI_NOT_FOUND The specified file could not be found on the + device or the file system could not be found + on the device. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_MEDIA_CHANGED The device has a different medium in it or the + medium is no longer supported. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The file or medium is write protected. + @retval EFI_ACCESS_DENIED The file was opened read only. + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the + file. + @retval EFI_VOLUME_FULL The volume is full. + @sa ShellOpenFileByName +**/ +EFI_STATUS +EFIAPI +ShellCreateDirectory( + IN CONST CHAR16 *DirectoryName, + OUT SHELL_FILE_HANDLE *FileHandle + ) +{ + if (gEfiShellProtocol != NULL) { + // + // Use UEFI Shell 2.0 method + // + return (gEfiShellProtocol->CreateFile(DirectoryName, + EFI_FILE_DIRECTORY, + FileHandle + )); + } else { + return (ShellOpenFileByName(DirectoryName, + FileHandle, + EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, + EFI_FILE_DIRECTORY + )); + } +} + +/** + This function reads information from an opened file. + + If FileHandle is not a directory, the function reads the requested number of + bytes from the file at the file's current position and returns them in Buffer. + If the read goes beyond the end of the file, the read length is truncated to the + end of the file. The file's current position is increased by the number of bytes + returned. If FileHandle is a directory, the function reads the directory entry + at the file's current position and returns the entry in Buffer. If the Buffer + is not large enough to hold the current directory entry, then + EFI_BUFFER_TOO_SMALL is returned and the current file position is not updated. + BufferSize is set to be the size of the buffer needed to read the entry. On + success, the current position is updated to the next directory entry. If there + are no more directory entries, the read returns a zero-length buffer. + EFI_FILE_INFO is the structure returned as the directory entry. + + @param FileHandle the opened file handle + @param BufferSize on input the size of buffer in bytes. on return + the number of bytes written. + @param Buffer the buffer to put read data into. + + @retval EFI_SUCCESS Data was read. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_BUFFER_TO_SMALL Buffer is too small. ReadSize contains required + size. + +**/ +EFI_STATUS +EFIAPI +ShellReadFile( + IN SHELL_FILE_HANDLE FileHandle, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + return (FileFunctionMap.ReadFile(FileHandle, BufferSize, Buffer)); +} + + +/** + Write data to a file. + + This function writes the specified number of bytes to the file at the current + file position. The current file position is advanced the actual number of bytes + written, which is returned in BufferSize. Partial writes only occur when there + has been a data error during the write attempt (such as "volume space full"). + The file is automatically grown to hold the data if required. Direct writes to + opened directories are not supported. + + @param FileHandle The opened file for writing + @param BufferSize on input the number of bytes in Buffer. On output + the number of bytes written. + @param Buffer the buffer containing data to write is stored. + + @retval EFI_SUCCESS Data was written. + @retval EFI_UNSUPPORTED Writes to an open directory are not supported. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The device is write-protected. + @retval EFI_ACCESS_DENIED The file was open for read only. + @retval EFI_VOLUME_FULL The volume is full. +**/ +EFI_STATUS +EFIAPI +ShellWriteFile( + IN SHELL_FILE_HANDLE FileHandle, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + return (FileFunctionMap.WriteFile(FileHandle, BufferSize, Buffer)); +} + +/** + Close an open file handle. + + This function closes a specified file handle. All "dirty" cached file data is + flushed to the device, and the file is closed. In all cases the handle is + closed. + +@param FileHandle the file handle to close. + +@retval EFI_SUCCESS the file handle was closed sucessfully. +**/ +EFI_STATUS +EFIAPI +ShellCloseFile ( + IN SHELL_FILE_HANDLE *FileHandle + ) +{ + return (FileFunctionMap.CloseFile(*FileHandle)); +} + +/** + Delete a file and close the handle + + This function closes and deletes a file. In all cases the file handle is closed. + If the file cannot be deleted, the warning code EFI_WARN_DELETE_FAILURE is + returned, but the handle is still closed. + + @param FileHandle the file handle to delete + + @retval EFI_SUCCESS the file was closed sucessfully + @retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not + deleted + @retval INVALID_PARAMETER One of the parameters has an invalid value. +**/ +EFI_STATUS +EFIAPI +ShellDeleteFile ( + IN SHELL_FILE_HANDLE *FileHandle + ) +{ + return (FileFunctionMap.DeleteFile(*FileHandle)); +} + +/** + Set the current position in a file. + + This function sets the current file position for the handle to the position + supplied. With the exception of seeking to position 0xFFFFFFFFFFFFFFFF, only + absolute positioning is supported, and seeking past the end of the file is + allowed (a subsequent write would grow the file). Seeking to position + 0xFFFFFFFFFFFFFFFF causes the current position to be set to the end of the file. + If FileHandle is a directory, the only position that may be set is zero. This + has the effect of starting the read process of the directory entries over. + + @param FileHandle The file handle on which the position is being set + @param Position Byte position from begining of file + + @retval EFI_SUCCESS Operation completed sucessfully. + @retval EFI_UNSUPPORTED the seek request for non-zero is not valid on + directories. + @retval INVALID_PARAMETER One of the parameters has an invalid value. +**/ +EFI_STATUS +EFIAPI +ShellSetFilePosition ( + IN SHELL_FILE_HANDLE FileHandle, + IN UINT64 Position + ) +{ + return (FileFunctionMap.SetFilePosition(FileHandle, Position)); +} + +/** + Gets a file's current position + + This function retrieves the current file position for the file handle. For + directories, the current file position has no meaning outside of the file + system driver and as such the operation is not supported. An error is returned + if FileHandle is a directory. + + @param FileHandle The open file handle on which to get the position. + @param Position Byte position from begining of file. + + @retval EFI_SUCCESS the operation completed sucessfully. + @retval INVALID_PARAMETER One of the parameters has an invalid value. + @retval EFI_UNSUPPORTED the request is not valid on directories. +**/ +EFI_STATUS +EFIAPI +ShellGetFilePosition ( + IN SHELL_FILE_HANDLE FileHandle, + OUT UINT64 *Position + ) +{ + return (FileFunctionMap.GetFilePosition(FileHandle, Position)); +} +/** + Flushes data on a file + + This function flushes all modified data associated with a file to a device. + + @param FileHandle The file handle on which to flush data + + @retval EFI_SUCCESS The data was flushed. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The file or medium is write protected. + @retval EFI_ACCESS_DENIED The file was opened for read only. +**/ +EFI_STATUS +EFIAPI +ShellFlushFile ( + IN SHELL_FILE_HANDLE FileHandle + ) +{ + return (FileFunctionMap.FlushFile(FileHandle)); +} + +/** Retrieve first entry from a directory. + + This function takes an open directory handle and gets information from the + first entry in the directory. A buffer is allocated to contain + the information and a pointer to the buffer is returned in *Buffer. The + caller can use ShellFindNextFile() to get subsequent directory entries. + + The buffer will be freed by ShellFindNextFile() when the last directory + entry is read. Otherwise, the caller must free the buffer, using FreePool, + when finished with it. + + @param[in] DirHandle The file handle of the directory to search. + @param[out] Buffer The pointer to the buffer for the file's information. + + @retval EFI_SUCCESS Found the first file. + @retval EFI_NOT_FOUND Cannot find the directory. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @return Others status of ShellGetFileInfo, ShellSetFilePosition, + or ShellReadFile +**/ +EFI_STATUS +EFIAPI +ShellFindFirstFile ( + IN SHELL_FILE_HANDLE DirHandle, + OUT EFI_FILE_INFO **Buffer + ) +{ + // + // pass to file handle lib + // + return (FileHandleFindFirstFile(DirHandle, Buffer)); +} +/** Retrieve next entries from a directory. + + To use this function, the caller must first call the ShellFindFirstFile() + function to get the first directory entry. Subsequent directory entries are + retrieved by using the ShellFindNextFile() function. This function can + be called several times to get each entry from the directory. If the call of + ShellFindNextFile() retrieved the last directory entry, the next call of + this function will set *NoFile to TRUE and free the buffer. + + @param[in] DirHandle The file handle of the directory. + @param[out] Buffer The pointer to buffer for file's information. + @param[out] NoFile The pointer to boolean when last file is found. + + @retval EFI_SUCCESS Found the next file, or reached last file + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. +**/ +EFI_STATUS +EFIAPI +ShellFindNextFile( + IN SHELL_FILE_HANDLE DirHandle, + OUT EFI_FILE_INFO *Buffer, + OUT BOOLEAN *NoFile + ) +{ + // + // pass to file handle lib + // + return (FileHandleFindNextFile(DirHandle, Buffer, NoFile)); +} +/** + Retrieve the size of a file. + + if FileHandle is NULL then ASSERT() + if Size is NULL then ASSERT() + + This function extracts the file size info from the FileHandle's EFI_FILE_INFO + data. + + @param FileHandle file handle from which size is retrieved + @param Size pointer to size + + @retval EFI_SUCCESS operation was completed sucessfully + @retval EFI_DEVICE_ERROR cannot access the file +**/ +EFI_STATUS +EFIAPI +ShellGetFileSize ( + IN SHELL_FILE_HANDLE FileHandle, + OUT UINT64 *Size + ) +{ + return (FileFunctionMap.GetFileSize(FileHandle, Size)); +} +/** + Retrieves the status of the break execution flag + + this function is useful to check whether the application is being asked to halt by the shell. + + @retval TRUE the execution break is enabled + @retval FALSE the execution break is not enabled +**/ +BOOLEAN +EFIAPI +ShellGetExecutionBreakFlag( + VOID + ) +{ + // + // Check for UEFI Shell 2.0 protocols + // + if (gEfiShellProtocol != NULL) { + + // + // We are using UEFI Shell 2.0; see if the event has been triggered + // + if (gBS->CheckEvent(gEfiShellProtocol->ExecutionBreak) != EFI_SUCCESS) { + return (FALSE); + } + return (TRUE); + } + + // + // using EFI Shell; call the function to check + // + if (mEfiShellEnvironment2 != NULL) { + return (mEfiShellEnvironment2->GetExecutionBreak()); + } + + return (FALSE); +} +/** + return the value of an environment variable + + this function gets the value of the environment variable set by the + ShellSetEnvironmentVariable function + + @param EnvKey The key name of the environment variable. + + @retval NULL the named environment variable does not exist. + @return != NULL pointer to the value of the environment variable +**/ +CONST CHAR16* +EFIAPI +ShellGetEnvironmentVariable ( + IN CONST CHAR16 *EnvKey + ) +{ + // + // Check for UEFI Shell 2.0 protocols + // + if (gEfiShellProtocol != NULL) { + return (gEfiShellProtocol->GetEnv(EnvKey)); + } + + // + // Check for EFI shell + // + if (mEfiShellEnvironment2 != NULL) { + return (mEfiShellEnvironment2->GetEnv((CHAR16*)EnvKey)); + } + + return NULL; +} +/** + set the value of an environment variable + +This function changes the current value of the specified environment variable. If the +environment variable exists and the Value is an empty string, then the environment +variable is deleted. If the environment variable exists and the Value is not an empty +string, then the value of the environment variable is changed. If the environment +variable does not exist and the Value is an empty string, there is no action. If the +environment variable does not exist and the Value is a non-empty string, then the +environment variable is created and assigned the specified value. + + This is not supported pre-UEFI Shell 2.0. + + @param EnvKey The key name of the environment variable. + @param EnvVal The Value of the environment variable + @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE). + + @retval EFI_SUCCESS the operation was completed sucessfully + @retval EFI_UNSUPPORTED This operation is not allowed in pre UEFI 2.0 Shell environments +**/ +EFI_STATUS +EFIAPI +ShellSetEnvironmentVariable ( + IN CONST CHAR16 *EnvKey, + IN CONST CHAR16 *EnvVal, + IN BOOLEAN Volatile + ) +{ + // + // Check for UEFI Shell 2.0 protocols + // + if (gEfiShellProtocol != NULL) { + return (gEfiShellProtocol->SetEnv(EnvKey, EnvVal, Volatile)); + } + + // + // This feature does not exist under EFI shell + // + return (EFI_UNSUPPORTED); +} + +/** + Cause the shell to parse and execute a command line. + + This function creates a nested instance of the shell and executes the specified + command (CommandLine) with the specified environment (Environment). Upon return, + the status code returned by the specified command is placed in StatusCode. + If Environment is NULL, then the current environment is used and all changes made + by the commands executed will be reflected in the current environment. If the + Environment is non-NULL, then the changes made will be discarded. + The CommandLine is executed from the current working directory on the current + device. + + The EnvironmentVariables pararemeter is ignored in a pre-UEFI Shell 2.0 + environment. The values pointed to by the parameters will be unchanged by the + ShellExecute() function. The Output parameter has no effect in a + UEFI Shell 2.0 environment. + + @param[in] ParentHandle The parent image starting the operation. + @param[in] CommandLine The pointer to a NULL terminated command line. + @param[in] Output True to display debug output. False to hide it. + @param[in] EnvironmentVariables Optional pointer to array of environment variables + in the form "x=y". If NULL, the current set is used. + @param[out] Status The status of the run command line. + + @retval EFI_SUCCESS The operation completed sucessfully. Status + contains the status code returned. + @retval EFI_INVALID_PARAMETER A parameter contains an invalid value. + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_UNSUPPORTED The operation is not allowed. +**/ +EFI_STATUS +EFIAPI +ShellExecute ( + IN EFI_HANDLE *ParentHandle, + IN CHAR16 *CommandLine OPTIONAL, + IN BOOLEAN Output OPTIONAL, + IN CHAR16 **EnvironmentVariables OPTIONAL, + OUT EFI_STATUS *Status OPTIONAL + ) +{ + EFI_STATUS CmdStatus; + // + // Check for UEFI Shell 2.0 protocols + // + if (gEfiShellProtocol != NULL) { + // + // Call UEFI Shell 2.0 version (not using Output parameter) + // + return (gEfiShellProtocol->Execute(ParentHandle, + CommandLine, + EnvironmentVariables, + Status)); + } + + // + // Check for EFI shell + // + if (mEfiShellEnvironment2 != NULL) { + // + // Call EFI Shell version. + // + // Due to an unfixable bug in the EdkShell implementation, we must + // dereference "ParentHandle" here: + // + // 1. The EFI shell installs the EFI_SHELL_ENVIRONMENT2 protocol, + // identified by gEfiShellEnvironment2Guid. + // 2. The Execute() member function takes "ParentImageHandle" as first + // parameter, with type (EFI_HANDLE*). + // 3. In the EdkShell implementation, SEnvExecute() implements the + // Execute() member function. It passes "ParentImageHandle" correctly to + // SEnvDoExecute(). + // 4. SEnvDoExecute() takes the (EFI_HANDLE*), and passes it directly -- + // without de-referencing -- to the HandleProtocol() boot service. + // 5. But HandleProtocol() takes an EFI_HANDLE. + // + // Therefore we must + // - de-reference "ParentHandle" here, to mask the bug in + // SEnvDoExecute(), and + // - pass the resultant EFI_HANDLE as an (EFI_HANDLE*). + // + CmdStatus = (mEfiShellEnvironment2->Execute((EFI_HANDLE *)*ParentHandle, + CommandLine, + Output)); + // + // No Status output parameter so just use the returned status + // + if (Status != NULL) { + *Status = CmdStatus; + } + // + // If there was an error, we can't tell if it was from the command or from + // the Execute() function, so we'll just assume the shell ran successfully + // and the error came from the command. + // + return EFI_SUCCESS; + } + + return (EFI_UNSUPPORTED); +} + +/** + Retreives the current directory path + + If the DeviceName is NULL, it returns the current device's current directory + name. If the DeviceName is not NULL, it returns the current directory name + on specified drive. + + Note that the current directory string should exclude the tailing backslash character. + + @param DeviceName the name of the drive to get directory on + + @retval NULL the directory does not exist + @return != NULL the directory +**/ +CONST CHAR16* +EFIAPI +ShellGetCurrentDir ( + IN CHAR16 * CONST DeviceName OPTIONAL + ) +{ + // + // Check for UEFI Shell 2.0 protocols + // + if (gEfiShellProtocol != NULL) { + return (gEfiShellProtocol->GetCurDir(DeviceName)); + } + + // + // Check for EFI shell + // + if (mEfiShellEnvironment2 != NULL) { + return (mEfiShellEnvironment2->CurDir(DeviceName)); + } + + return (NULL); +} +/** + sets (enabled or disabled) the page break mode + + when page break mode is enabled the screen will stop scrolling + and wait for operator input before scrolling a subsequent screen. + + @param CurrentState TRUE to enable and FALSE to disable +**/ +VOID +EFIAPI +ShellSetPageBreakMode ( + IN BOOLEAN CurrentState + ) +{ + // + // check for enabling + // + if (CurrentState != 0x00) { + // + // check for UEFI Shell 2.0 + // + if (gEfiShellProtocol != NULL) { + // + // Enable with UEFI 2.0 Shell + // + gEfiShellProtocol->EnablePageBreak(); + return; + } else { + // + // Check for EFI shell + // + if (mEfiShellEnvironment2 != NULL) { + // + // Enable with EFI Shell + // + mEfiShellEnvironment2->EnablePageBreak (DEFAULT_INIT_ROW, DEFAULT_AUTO_LF); + return; + } + } + } else { + // + // check for UEFI Shell 2.0 + // + if (gEfiShellProtocol != NULL) { + // + // Disable with UEFI 2.0 Shell + // + gEfiShellProtocol->DisablePageBreak(); + return; + } else { + // + // Check for EFI shell + // + if (mEfiShellEnvironment2 != NULL) { + // + // Disable with EFI Shell + // + mEfiShellEnvironment2->DisablePageBreak (); + return; + } + } + } +} + +/// +/// version of EFI_SHELL_FILE_INFO struct, except has no CONST pointers. +/// This allows for the struct to be populated. +/// +typedef struct { + LIST_ENTRY Link; + EFI_STATUS Status; + CHAR16 *FullName; + CHAR16 *FileName; + SHELL_FILE_HANDLE Handle; + EFI_FILE_INFO *Info; +} EFI_SHELL_FILE_INFO_NO_CONST; + +/** + Converts a EFI shell list of structures to the coresponding UEFI Shell 2.0 type of list. + + if OldStyleFileList is NULL then ASSERT() + + this function will convert a SHELL_FILE_ARG based list into a callee allocated + EFI_SHELL_FILE_INFO based list. it is up to the caller to free the memory via + the ShellCloseFileMetaArg function. + + @param[in] FileList the EFI shell list type + @param[in, out] ListHead the list to add to + + @retval the resultant head of the double linked new format list; +**/ +LIST_ENTRY* +InternalShellConvertFileListType ( + IN LIST_ENTRY *FileList, + IN OUT LIST_ENTRY *ListHead + ) +{ + SHELL_FILE_ARG *OldInfo; + LIST_ENTRY *Link; + EFI_SHELL_FILE_INFO_NO_CONST *NewInfo; + + // + // ASSERTs + // + ASSERT(FileList != NULL); + ASSERT(ListHead != NULL); + + // + // enumerate through each member of the old list and copy + // + for (Link = FileList->ForwardLink; Link != FileList; Link = Link->ForwardLink) { + OldInfo = CR (Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE); + ASSERT(OldInfo != NULL); + + // + // Skip ones that failed to open... + // + if (OldInfo->Status != EFI_SUCCESS) { + continue; + } + + // + // make sure the old list was valid + // + ASSERT(OldInfo->Info != NULL); + ASSERT(OldInfo->FullName != NULL); + ASSERT(OldInfo->FileName != NULL); + + // + // allocate a new EFI_SHELL_FILE_INFO object + // + NewInfo = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO)); + if (NewInfo == NULL) { + ShellCloseFileMetaArg((EFI_SHELL_FILE_INFO**)(&ListHead)); + ListHead = NULL; + break; + } + + // + // copy the simple items + // + NewInfo->Handle = OldInfo->Handle; + NewInfo->Status = OldInfo->Status; + + // old shell checks for 0 not NULL + OldInfo->Handle = 0; + + // + // allocate new space to copy strings and structure + // + NewInfo->FullName = AllocateCopyPool(StrSize(OldInfo->FullName), OldInfo->FullName); + NewInfo->FileName = AllocateCopyPool(StrSize(OldInfo->FileName), OldInfo->FileName); + NewInfo->Info = AllocateCopyPool((UINTN)OldInfo->Info->Size, OldInfo->Info); + + // + // make sure all the memory allocations were sucessful + // + if (NULL == NewInfo->FullName || NewInfo->FileName == NULL || NewInfo->Info == NULL) { + // + // Free the partially allocated new node + // + SHELL_FREE_NON_NULL(NewInfo->FullName); + SHELL_FREE_NON_NULL(NewInfo->FileName); + SHELL_FREE_NON_NULL(NewInfo->Info); + SHELL_FREE_NON_NULL(NewInfo); + + // + // Free the previously converted stuff + // + ShellCloseFileMetaArg((EFI_SHELL_FILE_INFO**)(&ListHead)); + ListHead = NULL; + break; + } + + // + // add that to the list + // + InsertTailList(ListHead, &NewInfo->Link); + } + return (ListHead); +} +/** + Opens a group of files based on a path. + + This function uses the Arg to open all the matching files. Each matched + file has a SHELL_FILE_INFO structure to record the file information. These + structures are placed on the list ListHead. Users can get the SHELL_FILE_INFO + structures from ListHead to access each file. This function supports wildcards + and will process '?' and '*' as such. the list must be freed with a call to + ShellCloseFileMetaArg(). + + If you are NOT appending to an existing list *ListHead must be NULL. If + *ListHead is NULL then it must be callee freed. + + @param Arg pointer to path string + @param OpenMode mode to open files with + @param ListHead head of linked list of results + + @retval EFI_SUCCESS the operation was sucessful and the list head + contains the list of opened files + @return != EFI_SUCCESS the operation failed + + @sa InternalShellConvertFileListType +**/ +EFI_STATUS +EFIAPI +ShellOpenFileMetaArg ( + IN CHAR16 *Arg, + IN UINT64 OpenMode, + IN OUT EFI_SHELL_FILE_INFO **ListHead + ) +{ + EFI_STATUS Status; + LIST_ENTRY mOldStyleFileList; + CHAR16 *CleanFilePathStr; + + // + // ASSERT that Arg and ListHead are not NULL + // + ASSERT(Arg != NULL); + ASSERT(ListHead != NULL); + + CleanFilePathStr = NULL; + + Status = InternalShellStripQuotes (Arg, &CleanFilePathStr); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Check for UEFI Shell 2.0 protocols + // + if (gEfiShellProtocol != NULL) { + if (*ListHead == NULL) { + *ListHead = (EFI_SHELL_FILE_INFO*)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO)); + if (*ListHead == NULL) { + FreePool(CleanFilePathStr); + return (EFI_OUT_OF_RESOURCES); + } + InitializeListHead(&((*ListHead)->Link)); + } + Status = gEfiShellProtocol->OpenFileList(CleanFilePathStr, + OpenMode, + ListHead); + if (EFI_ERROR(Status)) { + gEfiShellProtocol->RemoveDupInFileList(ListHead); + } else { + Status = gEfiShellProtocol->RemoveDupInFileList(ListHead); + } + if (*ListHead != NULL && IsListEmpty(&(*ListHead)->Link)) { + FreePool(*ListHead); + FreePool(CleanFilePathStr); + *ListHead = NULL; + return (EFI_NOT_FOUND); + } + FreePool(CleanFilePathStr); + return (Status); + } + + // + // Check for EFI shell + // + if (mEfiShellEnvironment2 != NULL) { + // + // make sure the list head is initialized + // + InitializeListHead(&mOldStyleFileList); + + // + // Get the EFI Shell list of files + // + Status = mEfiShellEnvironment2->FileMetaArg(CleanFilePathStr, &mOldStyleFileList); + if (EFI_ERROR(Status)) { + *ListHead = NULL; + FreePool(CleanFilePathStr); + return (Status); + } + + if (*ListHead == NULL) { + *ListHead = (EFI_SHELL_FILE_INFO *)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO)); + if (*ListHead == NULL) { + FreePool(CleanFilePathStr); + return (EFI_OUT_OF_RESOURCES); + } + InitializeListHead(&((*ListHead)->Link)); + } + + // + // Convert that to equivalent of UEFI Shell 2.0 structure + // + InternalShellConvertFileListType(&mOldStyleFileList, &(*ListHead)->Link); + + // + // Free the EFI Shell version that was converted. + // + mEfiShellEnvironment2->FreeFileList(&mOldStyleFileList); + + if ((*ListHead)->Link.ForwardLink == (*ListHead)->Link.BackLink && (*ListHead)->Link.BackLink == &((*ListHead)->Link)) { + FreePool(*ListHead); + *ListHead = NULL; + Status = EFI_NOT_FOUND; + } + FreePool(CleanFilePathStr); + return (Status); + } + + FreePool(CleanFilePathStr); + return (EFI_UNSUPPORTED); +} +/** + Free the linked list returned from ShellOpenFileMetaArg. + + if ListHead is NULL then ASSERT(). + + @param ListHead the pointer to free. + + @retval EFI_SUCCESS the operation was sucessful. +**/ +EFI_STATUS +EFIAPI +ShellCloseFileMetaArg ( + IN OUT EFI_SHELL_FILE_INFO **ListHead + ) +{ + LIST_ENTRY *Node; + + // + // ASSERT that ListHead is not NULL + // + ASSERT(ListHead != NULL); + + // + // Check for UEFI Shell 2.0 protocols + // + if (gEfiShellProtocol != NULL) { + return (gEfiShellProtocol->FreeFileList(ListHead)); + } else if (mEfiShellEnvironment2 != NULL) { + // + // Since this is EFI Shell version we need to free our internally made copy + // of the list + // + for ( Node = GetFirstNode(&(*ListHead)->Link) + ; *ListHead != NULL && !IsListEmpty(&(*ListHead)->Link) + ; Node = GetFirstNode(&(*ListHead)->Link)) { + RemoveEntryList(Node); + ((EFI_FILE_PROTOCOL*)((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Handle)->Close(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Handle); + FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->FullName); + FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->FileName); + FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Info); + FreePool((EFI_SHELL_FILE_INFO_NO_CONST*)Node); + } + SHELL_FREE_NON_NULL(*ListHead); + return EFI_SUCCESS; + } + + return (EFI_UNSUPPORTED); +} + +/** + Find a file by searching the CWD and then the path. + + If FileName is NULL then ASSERT. + + If the return value is not NULL then the memory must be caller freed. + + @param FileName Filename string. + + @retval NULL the file was not found + @return !NULL the full path to the file. +**/ +CHAR16 * +EFIAPI +ShellFindFilePath ( + IN CONST CHAR16 *FileName + ) +{ + CONST CHAR16 *Path; + SHELL_FILE_HANDLE Handle; + EFI_STATUS Status; + CHAR16 *RetVal; + CHAR16 *TestPath; + CONST CHAR16 *Walker; + UINTN Size; + CHAR16 *TempChar; + + RetVal = NULL; + + // + // First make sure its not an absolute path. + // + Status = ShellOpenFileByName(FileName, &Handle, EFI_FILE_MODE_READ, 0); + if (!EFI_ERROR(Status)){ + if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) { + ASSERT(RetVal == NULL); + RetVal = StrnCatGrow(&RetVal, NULL, FileName, 0); + ShellCloseFile(&Handle); + return (RetVal); + } else { + ShellCloseFile(&Handle); + } + } + + Path = ShellGetEnvironmentVariable(L"cwd"); + if (Path != NULL) { + Size = StrSize(Path) + sizeof(CHAR16); + Size += StrSize(FileName); + TestPath = AllocateZeroPool(Size); + if (TestPath == NULL) { + return (NULL); + } + StrCpyS(TestPath, Size/sizeof(CHAR16), Path); + StrCatS(TestPath, Size/sizeof(CHAR16), L"\\"); + StrCatS(TestPath, Size/sizeof(CHAR16), FileName); + Status = ShellOpenFileByName(TestPath, &Handle, EFI_FILE_MODE_READ, 0); + if (!EFI_ERROR(Status)){ + if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) { + ASSERT(RetVal == NULL); + RetVal = StrnCatGrow(&RetVal, NULL, TestPath, 0); + ShellCloseFile(&Handle); + FreePool(TestPath); + return (RetVal); + } else { + ShellCloseFile(&Handle); + } + } + FreePool(TestPath); + } + Path = ShellGetEnvironmentVariable(L"path"); + if (Path != NULL) { + Size = StrSize(Path)+sizeof(CHAR16); + Size += StrSize(FileName); + TestPath = AllocateZeroPool(Size); + if (TestPath == NULL) { + return (NULL); + } + Walker = (CHAR16*)Path; + do { + CopyMem(TestPath, Walker, StrSize(Walker)); + if (TestPath != NULL) { + TempChar = StrStr(TestPath, L";"); + if (TempChar != NULL) { + *TempChar = CHAR_NULL; + } + if (TestPath[StrLen(TestPath)-1] != L'\\') { + StrCatS(TestPath, Size/sizeof(CHAR16), L"\\"); + } + if (FileName[0] == L'\\') { + FileName++; + } + StrCatS(TestPath, Size/sizeof(CHAR16), FileName); + if (StrStr(Walker, L";") != NULL) { + Walker = StrStr(Walker, L";") + 1; + } else { + Walker = NULL; + } + Status = ShellOpenFileByName(TestPath, &Handle, EFI_FILE_MODE_READ, 0); + if (!EFI_ERROR(Status)){ + if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) { + ASSERT(RetVal == NULL); + RetVal = StrnCatGrow(&RetVal, NULL, TestPath, 0); + ShellCloseFile(&Handle); + break; + } else { + ShellCloseFile(&Handle); + } + } + } + } while (Walker != NULL && Walker[0] != CHAR_NULL); + FreePool(TestPath); + } + return (RetVal); +} + +/** + Find a file by searching the CWD and then the path with a variable set of file + extensions. If the file is not found it will append each extension in the list + in the order provided and return the first one that is successful. + + If FileName is NULL, then ASSERT. + If FileExtension is NULL, then behavior is identical to ShellFindFilePath. + + If the return value is not NULL then the memory must be caller freed. + + @param[in] FileName Filename string. + @param[in] FileExtension Semi-colon delimeted list of possible extensions. + + @retval NULL The file was not found. + @retval !NULL The path to the file. +**/ +CHAR16 * +EFIAPI +ShellFindFilePathEx ( + IN CONST CHAR16 *FileName, + IN CONST CHAR16 *FileExtension + ) +{ + CHAR16 *TestPath; + CHAR16 *RetVal; + CONST CHAR16 *ExtensionWalker; + UINTN Size; + CHAR16 *TempChar; + CHAR16 *TempChar2; + + ASSERT(FileName != NULL); + if (FileExtension == NULL) { + return (ShellFindFilePath(FileName)); + } + RetVal = ShellFindFilePath(FileName); + if (RetVal != NULL) { + return (RetVal); + } + Size = StrSize(FileName); + Size += StrSize(FileExtension); + TestPath = AllocateZeroPool(Size); + if (TestPath == NULL) { + return (NULL); + } + for (ExtensionWalker = FileExtension, TempChar2 = (CHAR16*)FileExtension; TempChar2 != NULL ; ExtensionWalker = TempChar2 + 1){ + StrCpyS(TestPath, Size/sizeof(CHAR16), FileName); + if (ExtensionWalker != NULL) { + StrCatS(TestPath, Size/sizeof(CHAR16), ExtensionWalker); + } + TempChar = StrStr(TestPath, L";"); + if (TempChar != NULL) { + *TempChar = CHAR_NULL; + } + RetVal = ShellFindFilePath(TestPath); + if (RetVal != NULL) { + break; + } + ASSERT(ExtensionWalker != NULL); + TempChar2 = StrStr(ExtensionWalker, L";"); + } + FreePool(TestPath); + return (RetVal); +} + +typedef struct { + LIST_ENTRY Link; + CHAR16 *Name; + SHELL_PARAM_TYPE Type; + CHAR16 *Value; + UINTN OriginalPosition; +} SHELL_PARAM_PACKAGE; + +/** + Checks the list of valid arguments and returns TRUE if the item was found. If the + return value is TRUE then the type parameter is set also. + + if CheckList is NULL then ASSERT(); + if Name is NULL then ASSERT(); + if Type is NULL then ASSERT(); + + @param Name pointer to Name of parameter found + @param CheckList List to check against + @param Type pointer to type of parameter if it was found + + @retval TRUE the Parameter was found. Type is valid. + @retval FALSE the Parameter was not found. Type is not valid. +**/ +BOOLEAN +InternalIsOnCheckList ( + IN CONST CHAR16 *Name, + IN CONST SHELL_PARAM_ITEM *CheckList, + OUT SHELL_PARAM_TYPE *Type + ) +{ + SHELL_PARAM_ITEM *TempListItem; + CHAR16 *TempString; + + // + // ASSERT that all 3 pointer parameters aren't NULL + // + ASSERT(CheckList != NULL); + ASSERT(Type != NULL); + ASSERT(Name != NULL); + + // + // question mark and page break mode are always supported + // + if ((StrCmp(Name, L"-?") == 0) || + (StrCmp(Name, L"-b") == 0) + ) { + *Type = TypeFlag; + return (TRUE); + } + + // + // Enumerate through the list + // + for (TempListItem = (SHELL_PARAM_ITEM*)CheckList ; TempListItem->Name != NULL ; TempListItem++) { + // + // If the Type is TypeStart only check the first characters of the passed in param + // If it matches set the type and return TRUE + // + if (TempListItem->Type == TypeStart) { + if (StrnCmp(Name, TempListItem->Name, StrLen(TempListItem->Name)) == 0) { + *Type = TempListItem->Type; + return (TRUE); + } + TempString = NULL; + TempString = StrnCatGrow(&TempString, NULL, Name, StrLen(TempListItem->Name)); + if (TempString != NULL) { + if (StringNoCaseCompare(&TempString, &TempListItem->Name) == 0) { + *Type = TempListItem->Type; + FreePool(TempString); + return (TRUE); + } + FreePool(TempString); + } + } else if (StringNoCaseCompare(&Name, &TempListItem->Name) == 0) { + *Type = TempListItem->Type; + return (TRUE); + } + } + + return (FALSE); +} +/** + Checks the string for indicators of "flag" status. this is a leading '/', '-', or '+' + + @param[in] Name pointer to Name of parameter found + @param[in] AlwaysAllowNumbers TRUE to allow numbers, FALSE to not. + @param[in] TimeNumbers TRUE to allow numbers with ":", FALSE otherwise. + + @retval TRUE the Parameter is a flag. + @retval FALSE the Parameter not a flag. +**/ +BOOLEAN +InternalIsFlag ( + IN CONST CHAR16 *Name, + IN CONST BOOLEAN AlwaysAllowNumbers, + IN CONST BOOLEAN TimeNumbers + ) +{ + // + // ASSERT that Name isn't NULL + // + ASSERT(Name != NULL); + + // + // If we accept numbers then dont return TRUE. (they will be values) + // + if (((Name[0] == L'-' || Name[0] == L'+') && InternalShellIsHexOrDecimalNumber(Name+1, FALSE, FALSE, TimeNumbers)) && AlwaysAllowNumbers) { + return (FALSE); + } + + // + // If the Name has a /, +, or - as the first character return TRUE + // + if ((Name[0] == L'/') || + (Name[0] == L'-') || + (Name[0] == L'+') + ) { + return (TRUE); + } + return (FALSE); +} + +/** + Checks the command line arguments passed against the list of valid ones. + + If no initialization is required, then return RETURN_SUCCESS. + + @param[in] CheckList pointer to list of parameters to check + @param[out] CheckPackage pointer to pointer to list checked values + @param[out] ProblemParam optional pointer to pointer to unicode string for + the paramater that caused failure. If used then the + caller is responsible for freeing the memory. + @param[in] AutoPageBreak will automatically set PageBreakEnabled for "b" parameter + @param[in] Argv pointer to array of parameters + @param[in] Argc Count of parameters in Argv + @param[in] AlwaysAllowNumbers TRUE to allow numbers always, FALSE otherwise. + + @retval EFI_SUCCESS The operation completed sucessfully. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed + @retval EFI_INVALID_PARAMETER A parameter was invalid + @retval EFI_VOLUME_CORRUPTED the command line was corrupt. an argument was + duplicated. the duplicated command line argument + was returned in ProblemParam if provided. + @retval EFI_NOT_FOUND a argument required a value that was missing. + the invalid command line argument was returned in + ProblemParam if provided. +**/ +EFI_STATUS +InternalCommandLineParse ( + IN CONST SHELL_PARAM_ITEM *CheckList, + OUT LIST_ENTRY **CheckPackage, + OUT CHAR16 **ProblemParam OPTIONAL, + IN BOOLEAN AutoPageBreak, + IN CONST CHAR16 **Argv, + IN UINTN Argc, + IN BOOLEAN AlwaysAllowNumbers + ) +{ + UINTN LoopCounter; + SHELL_PARAM_TYPE CurrentItemType; + SHELL_PARAM_PACKAGE *CurrentItemPackage; + UINTN GetItemValue; + UINTN ValueSize; + UINTN Count; + CONST CHAR16 *TempPointer; + UINTN CurrentValueSize; + CHAR16 *NewValue; + + CurrentItemPackage = NULL; + GetItemValue = 0; + ValueSize = 0; + Count = 0; + + // + // If there is only 1 item we dont need to do anything + // + if (Argc < 1) { + *CheckPackage = NULL; + return (EFI_SUCCESS); + } + + // + // ASSERTs + // + ASSERT(CheckList != NULL); + ASSERT(Argv != NULL); + + // + // initialize the linked list + // + *CheckPackage = (LIST_ENTRY*)AllocateZeroPool(sizeof(LIST_ENTRY)); + if (*CheckPackage == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + InitializeListHead(*CheckPackage); + + // + // loop through each of the arguments + // + for (LoopCounter = 0 ; LoopCounter < Argc ; ++LoopCounter) { + if (Argv[LoopCounter] == NULL) { + // + // do nothing for NULL argv + // + } else if (InternalIsOnCheckList(Argv[LoopCounter], CheckList, &CurrentItemType)) { + // + // We might have leftover if last parameter didnt have optional value + // + if (GetItemValue != 0) { + GetItemValue = 0; + InsertHeadList(*CheckPackage, &CurrentItemPackage->Link); + } + // + // this is a flag + // + CurrentItemPackage = AllocateZeroPool(sizeof(SHELL_PARAM_PACKAGE)); + if (CurrentItemPackage == NULL) { + ShellCommandLineFreeVarList(*CheckPackage); + *CheckPackage = NULL; + return (EFI_OUT_OF_RESOURCES); + } + CurrentItemPackage->Name = AllocateCopyPool(StrSize(Argv[LoopCounter]), Argv[LoopCounter]); + if (CurrentItemPackage->Name == NULL) { + ShellCommandLineFreeVarList(*CheckPackage); + *CheckPackage = NULL; + return (EFI_OUT_OF_RESOURCES); + } + CurrentItemPackage->Type = CurrentItemType; + CurrentItemPackage->OriginalPosition = (UINTN)(-1); + CurrentItemPackage->Value = NULL; + + // + // Does this flag require a value + // + switch (CurrentItemPackage->Type) { + // + // possibly trigger the next loop(s) to populate the value of this item + // + case TypeValue: + case TypeTimeValue: + GetItemValue = 1; + ValueSize = 0; + break; + case TypeDoubleValue: + GetItemValue = 2; + ValueSize = 0; + break; + case TypeMaxValue: + GetItemValue = (UINTN)(-1); + ValueSize = 0; + break; + default: + // + // this item has no value expected; we are done + // + InsertHeadList(*CheckPackage, &CurrentItemPackage->Link); + ASSERT(GetItemValue == 0); + break; + } + } else if (GetItemValue != 0 && CurrentItemPackage != NULL && !InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers, (BOOLEAN)(CurrentItemPackage->Type == TypeTimeValue))) { + // + // get the item VALUE for a previous flag + // + CurrentValueSize = ValueSize + StrSize(Argv[LoopCounter]) + sizeof(CHAR16); + NewValue = ReallocatePool(ValueSize, CurrentValueSize, CurrentItemPackage->Value); + if (NewValue == NULL) { + SHELL_FREE_NON_NULL (CurrentItemPackage->Value); + SHELL_FREE_NON_NULL (CurrentItemPackage); + ShellCommandLineFreeVarList (*CheckPackage); + *CheckPackage = NULL; + return EFI_OUT_OF_RESOURCES; + } + CurrentItemPackage->Value = NewValue; + if (ValueSize == 0) { + StrCpyS( CurrentItemPackage->Value, + CurrentValueSize/sizeof(CHAR16), + Argv[LoopCounter] + ); + } else { + StrCatS( CurrentItemPackage->Value, + CurrentValueSize/sizeof(CHAR16), + L" " + ); + StrCatS( CurrentItemPackage->Value, + CurrentValueSize/sizeof(CHAR16), + Argv[LoopCounter] + ); + } + ValueSize += StrSize(Argv[LoopCounter]) + sizeof(CHAR16); + + GetItemValue--; + if (GetItemValue == 0) { + InsertHeadList(*CheckPackage, &CurrentItemPackage->Link); + } + } else if (!InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers, FALSE)){ + // + // add this one as a non-flag + // + + TempPointer = Argv[LoopCounter]; + if ((*TempPointer == L'^' && *(TempPointer+1) == L'-') + || (*TempPointer == L'^' && *(TempPointer+1) == L'/') + || (*TempPointer == L'^' && *(TempPointer+1) == L'+') + ){ + TempPointer++; + } + CurrentItemPackage = AllocateZeroPool(sizeof(SHELL_PARAM_PACKAGE)); + if (CurrentItemPackage == NULL) { + ShellCommandLineFreeVarList(*CheckPackage); + *CheckPackage = NULL; + return (EFI_OUT_OF_RESOURCES); + } + CurrentItemPackage->Name = NULL; + CurrentItemPackage->Type = TypePosition; + CurrentItemPackage->Value = AllocateCopyPool(StrSize(TempPointer), TempPointer); + if (CurrentItemPackage->Value == NULL) { + ShellCommandLineFreeVarList(*CheckPackage); + *CheckPackage = NULL; + return (EFI_OUT_OF_RESOURCES); + } + CurrentItemPackage->OriginalPosition = Count++; + InsertHeadList(*CheckPackage, &CurrentItemPackage->Link); + } else { + // + // this was a non-recognised flag... error! + // + if (ProblemParam != NULL) { + *ProblemParam = AllocateCopyPool(StrSize(Argv[LoopCounter]), Argv[LoopCounter]); + } + ShellCommandLineFreeVarList(*CheckPackage); + *CheckPackage = NULL; + return (EFI_VOLUME_CORRUPTED); + } + } + if (GetItemValue != 0) { + GetItemValue = 0; + InsertHeadList(*CheckPackage, &CurrentItemPackage->Link); + } + // + // support for AutoPageBreak + // + if (AutoPageBreak && ShellCommandLineGetFlag(*CheckPackage, L"-b")) { + ShellSetPageBreakMode(TRUE); + } + return (EFI_SUCCESS); +} + +/** + Checks the command line arguments passed against the list of valid ones. + Optionally removes NULL values first. + + If no initialization is required, then return RETURN_SUCCESS. + + @param[in] CheckList The pointer to list of parameters to check. + @param[out] CheckPackage The package of checked values. + @param[out] ProblemParam Optional pointer to pointer to unicode string for + the paramater that caused failure. + @param[in] AutoPageBreak Will automatically set PageBreakEnabled. + @param[in] AlwaysAllowNumbers Will never fail for number based flags. + + @retval EFI_SUCCESS The operation completed sucessfully. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_INVALID_PARAMETER A parameter was invalid. + @retval EFI_VOLUME_CORRUPTED The command line was corrupt. + @retval EFI_DEVICE_ERROR The commands contained 2 opposing arguments. One + of the command line arguments was returned in + ProblemParam if provided. + @retval EFI_NOT_FOUND A argument required a value that was missing. + The invalid command line argument was returned in + ProblemParam if provided. +**/ +EFI_STATUS +EFIAPI +ShellCommandLineParseEx ( + IN CONST SHELL_PARAM_ITEM *CheckList, + OUT LIST_ENTRY **CheckPackage, + OUT CHAR16 **ProblemParam OPTIONAL, + IN BOOLEAN AutoPageBreak, + IN BOOLEAN AlwaysAllowNumbers + ) +{ + // + // ASSERT that CheckList and CheckPackage aren't NULL + // + ASSERT(CheckList != NULL); + ASSERT(CheckPackage != NULL); + + // + // Check for UEFI Shell 2.0 protocols + // + if (gEfiShellParametersProtocol != NULL) { + return (InternalCommandLineParse(CheckList, + CheckPackage, + ProblemParam, + AutoPageBreak, + (CONST CHAR16**) gEfiShellParametersProtocol->Argv, + gEfiShellParametersProtocol->Argc, + AlwaysAllowNumbers)); + } + + // + // ASSERT That EFI Shell is not required + // + ASSERT (mEfiShellInterface != NULL); + return (InternalCommandLineParse(CheckList, + CheckPackage, + ProblemParam, + AutoPageBreak, + (CONST CHAR16**) mEfiShellInterface->Argv, + mEfiShellInterface->Argc, + AlwaysAllowNumbers)); +} + +/** + Frees shell variable list that was returned from ShellCommandLineParse. + + This function will free all the memory that was used for the CheckPackage + list of postprocessed shell arguments. + + this function has no return value. + + if CheckPackage is NULL, then return + + @param CheckPackage the list to de-allocate + **/ +VOID +EFIAPI +ShellCommandLineFreeVarList ( + IN LIST_ENTRY *CheckPackage + ) +{ + LIST_ENTRY *Node; + + // + // check for CheckPackage == NULL + // + if (CheckPackage == NULL) { + return; + } + + // + // for each node in the list + // + for ( Node = GetFirstNode(CheckPackage) + ; !IsListEmpty(CheckPackage) + ; Node = GetFirstNode(CheckPackage) + ){ + // + // Remove it from the list + // + RemoveEntryList(Node); + + // + // if it has a name free the name + // + if (((SHELL_PARAM_PACKAGE*)Node)->Name != NULL) { + FreePool(((SHELL_PARAM_PACKAGE*)Node)->Name); + } + + // + // if it has a value free the value + // + if (((SHELL_PARAM_PACKAGE*)Node)->Value != NULL) { + FreePool(((SHELL_PARAM_PACKAGE*)Node)->Value); + } + + // + // free the node structure + // + FreePool((SHELL_PARAM_PACKAGE*)Node); + } + // + // free the list head node + // + FreePool(CheckPackage); +} +/** + Checks for presence of a flag parameter + + flag arguments are in the form of "-" or "/", but do not have a value following the key + + if CheckPackage is NULL then return FALSE. + if KeyString is NULL then ASSERT() + + @param CheckPackage The package of parsed command line arguments + @param KeyString the Key of the command line argument to check for + + @retval TRUE the flag is on the command line + @retval FALSE the flag is not on the command line + **/ +BOOLEAN +EFIAPI +ShellCommandLineGetFlag ( + IN CONST LIST_ENTRY * CONST CheckPackage, + IN CONST CHAR16 * CONST KeyString + ) +{ + LIST_ENTRY *Node; + CHAR16 *TempString; + + // + // return FALSE for no package or KeyString is NULL + // + if (CheckPackage == NULL || KeyString == NULL) { + return (FALSE); + } + + // + // enumerate through the list of parametrs + // + for ( Node = GetFirstNode(CheckPackage) + ; !IsNull (CheckPackage, Node) + ; Node = GetNextNode(CheckPackage, Node) + ){ + // + // If the Name matches, return TRUE (and there may be NULL name) + // + if (((SHELL_PARAM_PACKAGE*)Node)->Name != NULL) { + // + // If Type is TypeStart then only compare the begining of the strings + // + if (((SHELL_PARAM_PACKAGE*)Node)->Type == TypeStart) { + if (StrnCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name, StrLen(KeyString)) == 0) { + return (TRUE); + } + TempString = NULL; + TempString = StrnCatGrow(&TempString, NULL, KeyString, StrLen(((SHELL_PARAM_PACKAGE*)Node)->Name)); + if (TempString != NULL) { + if (StringNoCaseCompare(&KeyString, &((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) { + FreePool(TempString); + return (TRUE); + } + FreePool(TempString); + } + } else if (StringNoCaseCompare(&KeyString, &((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) { + return (TRUE); + } + } + } + return (FALSE); +} +/** + Returns value from command line argument. + + Value parameters are in the form of "- value" or "/ value". + + If CheckPackage is NULL, then return NULL. + + @param[in] CheckPackage The package of parsed command line arguments. + @param[in] KeyString The Key of the command line argument to check for. + + @retval NULL The flag is not on the command line. + @retval !=NULL The pointer to unicode string of the value. +**/ +CONST CHAR16* +EFIAPI +ShellCommandLineGetValue ( + IN CONST LIST_ENTRY *CheckPackage, + IN CHAR16 *KeyString + ) +{ + LIST_ENTRY *Node; + CHAR16 *TempString; + + // + // return NULL for no package or KeyString is NULL + // + if (CheckPackage == NULL || KeyString == NULL) { + return (NULL); + } + + // + // enumerate through the list of parametrs + // + for ( Node = GetFirstNode(CheckPackage) + ; !IsNull (CheckPackage, Node) + ; Node = GetNextNode(CheckPackage, Node) + ){ + // + // If the Name matches, return TRUE (and there may be NULL name) + // + if (((SHELL_PARAM_PACKAGE*)Node)->Name != NULL) { + // + // If Type is TypeStart then only compare the begining of the strings + // + if (((SHELL_PARAM_PACKAGE*)Node)->Type == TypeStart) { + if (StrnCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name, StrLen(KeyString)) == 0) { + return (((SHELL_PARAM_PACKAGE*)Node)->Name + StrLen(KeyString)); + } + TempString = NULL; + TempString = StrnCatGrow(&TempString, NULL, KeyString, StrLen(((SHELL_PARAM_PACKAGE*)Node)->Name)); + if (TempString != NULL) { + if (StringNoCaseCompare(&KeyString, &((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) { + FreePool(TempString); + return (((SHELL_PARAM_PACKAGE*)Node)->Name + StrLen(KeyString)); + } + FreePool(TempString); + } + } else if (StringNoCaseCompare(&KeyString, &((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) { + return (((SHELL_PARAM_PACKAGE*)Node)->Value); + } + } + } + return (NULL); +} + +/** + Returns raw value from command line argument. + + Raw value parameters are in the form of "value" in a specific position in the list. + + If CheckPackage is NULL, then return NULL. + + @param[in] CheckPackage The package of parsed command line arguments. + @param[in] Position The position of the value. + + @retval NULL The flag is not on the command line. + @retval !=NULL The pointer to unicode string of the value. + **/ +CONST CHAR16* +EFIAPI +ShellCommandLineGetRawValue ( + IN CONST LIST_ENTRY * CONST CheckPackage, + IN UINTN Position + ) +{ + LIST_ENTRY *Node; + + // + // check for CheckPackage == NULL + // + if (CheckPackage == NULL) { + return (NULL); + } + + // + // enumerate through the list of parametrs + // + for ( Node = GetFirstNode(CheckPackage) + ; !IsNull (CheckPackage, Node) + ; Node = GetNextNode(CheckPackage, Node) + ){ + // + // If the position matches, return the value + // + if (((SHELL_PARAM_PACKAGE*)Node)->OriginalPosition == Position) { + return (((SHELL_PARAM_PACKAGE*)Node)->Value); + } + } + return (NULL); +} + +/** + returns the number of command line value parameters that were parsed. + + this will not include flags. + + @param[in] CheckPackage The package of parsed command line arguments. + + @retval (UINTN)-1 No parsing has ocurred + @return other The number of value parameters found +**/ +UINTN +EFIAPI +ShellCommandLineGetCount( + IN CONST LIST_ENTRY *CheckPackage + ) +{ + LIST_ENTRY *Node1; + UINTN Count; + + if (CheckPackage == NULL) { + return (0); + } + for ( Node1 = GetFirstNode(CheckPackage), Count = 0 + ; !IsNull (CheckPackage, Node1) + ; Node1 = GetNextNode(CheckPackage, Node1) + ){ + if (((SHELL_PARAM_PACKAGE*)Node1)->Name == NULL) { + Count++; + } + } + return (Count); +} + +/** + Determines if a parameter is duplicated. + + If Param is not NULL then it will point to a callee allocated string buffer + with the parameter value if a duplicate is found. + + If CheckPackage is NULL, then ASSERT. + + @param[in] CheckPackage The package of parsed command line arguments. + @param[out] Param Upon finding one, a pointer to the duplicated parameter. + + @retval EFI_SUCCESS No parameters were duplicated. + @retval EFI_DEVICE_ERROR A duplicate was found. + **/ +EFI_STATUS +EFIAPI +ShellCommandLineCheckDuplicate ( + IN CONST LIST_ENTRY *CheckPackage, + OUT CHAR16 **Param + ) +{ + LIST_ENTRY *Node1; + LIST_ENTRY *Node2; + + ASSERT(CheckPackage != NULL); + + for ( Node1 = GetFirstNode(CheckPackage) + ; !IsNull (CheckPackage, Node1) + ; Node1 = GetNextNode(CheckPackage, Node1) + ){ + for ( Node2 = GetNextNode(CheckPackage, Node1) + ; !IsNull (CheckPackage, Node2) + ; Node2 = GetNextNode(CheckPackage, Node2) + ){ + if ((((SHELL_PARAM_PACKAGE*)Node1)->Name != NULL) && (((SHELL_PARAM_PACKAGE*)Node2)->Name != NULL) && StrCmp(((SHELL_PARAM_PACKAGE*)Node1)->Name, ((SHELL_PARAM_PACKAGE*)Node2)->Name) == 0) { + if (Param != NULL) { + *Param = NULL; + *Param = StrnCatGrow(Param, NULL, ((SHELL_PARAM_PACKAGE*)Node1)->Name, 0); + } + return (EFI_DEVICE_ERROR); + } + } + } + return (EFI_SUCCESS); +} + +/** + This is a find and replace function. Upon successful return the NewString is a copy of + SourceString with each instance of FindTarget replaced with ReplaceWith. + + If SourceString and NewString overlap the behavior is undefined. + + If the string would grow bigger than NewSize it will halt and return error. + + @param[in] SourceString The string with source buffer. + @param[in, out] NewString The string with resultant buffer. + @param[in] NewSize The size in bytes of NewString. + @param[in] FindTarget The string to look for. + @param[in] ReplaceWith The string to replace FindTarget with. + @param[in] SkipPreCarrot If TRUE will skip a FindTarget that has a '^' + immediately before it. + @param[in] ParameterReplacing If TRUE will add "" around items with spaces. + + @retval EFI_INVALID_PARAMETER SourceString was NULL. + @retval EFI_INVALID_PARAMETER NewString was NULL. + @retval EFI_INVALID_PARAMETER FindTarget was NULL. + @retval EFI_INVALID_PARAMETER ReplaceWith was NULL. + @retval EFI_INVALID_PARAMETER FindTarget had length < 1. + @retval EFI_INVALID_PARAMETER SourceString had length < 1. + @retval EFI_BUFFER_TOO_SMALL NewSize was less than the minimum size to hold + the new string (truncation occurred). + @retval EFI_SUCCESS The string was successfully copied with replacement. +**/ +EFI_STATUS +EFIAPI +ShellCopySearchAndReplace( + IN CHAR16 CONST *SourceString, + IN OUT CHAR16 *NewString, + IN UINTN NewSize, + IN CONST CHAR16 *FindTarget, + IN CONST CHAR16 *ReplaceWith, + IN CONST BOOLEAN SkipPreCarrot, + IN CONST BOOLEAN ParameterReplacing + ) +{ + UINTN Size; + CHAR16 *Replace; + + if ( (SourceString == NULL) + || (NewString == NULL) + || (FindTarget == NULL) + || (ReplaceWith == NULL) + || (StrLen(FindTarget) < 1) + || (StrLen(SourceString) < 1) + ){ + return (EFI_INVALID_PARAMETER); + } + Replace = NULL; + if (StrStr(ReplaceWith, L" ") == NULL || !ParameterReplacing) { + Replace = StrnCatGrow(&Replace, NULL, ReplaceWith, 0); + } else { + Replace = AllocateZeroPool(StrSize(ReplaceWith) + 2*sizeof(CHAR16)); + if (Replace != NULL) { + UnicodeSPrint(Replace, StrSize(ReplaceWith) + 2*sizeof(CHAR16), L"\"%s\"", ReplaceWith); + } + } + if (Replace == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + NewString = ZeroMem(NewString, NewSize); + while (*SourceString != CHAR_NULL) { + // + // if we find the FindTarget and either Skip == FALSE or Skip and we + // dont have a carrot do a replace... + // + if (StrnCmp(SourceString, FindTarget, StrLen(FindTarget)) == 0 + && ((SkipPreCarrot && *(SourceString-1) != L'^') || !SkipPreCarrot) + ){ + SourceString += StrLen(FindTarget); + Size = StrSize(NewString); + if ((Size + (StrLen(Replace)*sizeof(CHAR16))) > NewSize) { + FreePool(Replace); + return (EFI_BUFFER_TOO_SMALL); + } + StrCatS(NewString, NewSize/sizeof(CHAR16), Replace); + } else { + Size = StrSize(NewString); + if (Size + sizeof(CHAR16) > NewSize) { + FreePool(Replace); + return (EFI_BUFFER_TOO_SMALL); + } + StrnCatS(NewString, NewSize/sizeof(CHAR16), SourceString, 1); + SourceString++; + } + } + FreePool(Replace); + return (EFI_SUCCESS); +} + +/** + Internal worker function to output a string. + + This function will output a string to the correct StdOut. + + @param[in] String The string to print out. + + @retval EFI_SUCCESS The operation was sucessful. + @retval !EFI_SUCCESS The operation failed. +**/ +EFI_STATUS +InternalPrintTo ( + IN CONST CHAR16 *String + ) +{ + UINTN Size; + Size = StrSize(String) - sizeof(CHAR16); + if (Size == 0) { + return (EFI_SUCCESS); + } + if (gEfiShellParametersProtocol != NULL) { + return (gEfiShellProtocol->WriteFile(gEfiShellParametersProtocol->StdOut, &Size, (VOID*)String)); + } + if (mEfiShellInterface != NULL) { + if (mEfiShellInterface->RedirArgc == 0) { + // + // Divide in half for old shell. Must be string length not size. + // + Size /=2; // Divide in half only when no redirection. + } + return (mEfiShellInterface->StdOut->Write(mEfiShellInterface->StdOut, &Size, (VOID*)String)); + } + ASSERT(FALSE); + return (EFI_UNSUPPORTED); +} + +/** + Print at a specific location on the screen. + + This function will move the cursor to a given screen location and print the specified string + + If -1 is specified for either the Row or Col the current screen location for BOTH + will be used. + + if either Row or Col is out of range for the current console, then ASSERT + if Format is NULL, then ASSERT + + In addition to the standard %-based flags as supported by UefiLib Print() this supports + the following additional flags: + %N - Set output attribute to normal + %H - Set output attribute to highlight + %E - Set output attribute to error + %B - Set output attribute to blue color + %V - Set output attribute to green color + + Note: The background color is controlled by the shell command cls. + + @param[in] Col the column to print at + @param[in] Row the row to print at + @param[in] Format the format string + @param[in] Marker the marker for the variable argument list + + @return EFI_SUCCESS The operation was successful. + @return EFI_DEVICE_ERROR The console device reported an error. +**/ +EFI_STATUS +InternalShellPrintWorker( + IN INT32 Col OPTIONAL, + IN INT32 Row OPTIONAL, + IN CONST CHAR16 *Format, + IN VA_LIST Marker + ) +{ + EFI_STATUS Status; + CHAR16 *ResumeLocation; + CHAR16 *FormatWalker; + UINTN OriginalAttribute; + CHAR16 *mPostReplaceFormat; + CHAR16 *mPostReplaceFormat2; + + mPostReplaceFormat = AllocateZeroPool (PcdGet16 (PcdShellPrintBufferSize)); + mPostReplaceFormat2 = AllocateZeroPool (PcdGet16 (PcdShellPrintBufferSize)); + + if (mPostReplaceFormat == NULL || mPostReplaceFormat2 == NULL) { + SHELL_FREE_NON_NULL(mPostReplaceFormat); + SHELL_FREE_NON_NULL(mPostReplaceFormat2); + return (EFI_OUT_OF_RESOURCES); + } + + Status = EFI_SUCCESS; + OriginalAttribute = gST->ConOut->Mode->Attribute; + + // + // Back and forth each time fixing up 1 of our flags... + // + Status = ShellCopySearchAndReplace(Format, mPostReplaceFormat, PcdGet16 (PcdShellPrintBufferSize), L"%N", L"%%N", FALSE, FALSE); + ASSERT_EFI_ERROR(Status); + Status = ShellCopySearchAndReplace(mPostReplaceFormat, mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), L"%E", L"%%E", FALSE, FALSE); + ASSERT_EFI_ERROR(Status); + Status = ShellCopySearchAndReplace(mPostReplaceFormat2, mPostReplaceFormat, PcdGet16 (PcdShellPrintBufferSize), L"%H", L"%%H", FALSE, FALSE); + ASSERT_EFI_ERROR(Status); + Status = ShellCopySearchAndReplace(mPostReplaceFormat, mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), L"%B", L"%%B", FALSE, FALSE); + ASSERT_EFI_ERROR(Status); + Status = ShellCopySearchAndReplace(mPostReplaceFormat2, mPostReplaceFormat, PcdGet16 (PcdShellPrintBufferSize), L"%V", L"%%V", FALSE, FALSE); + ASSERT_EFI_ERROR(Status); + + // + // Use the last buffer from replacing to print from... + // + UnicodeVSPrint (mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), mPostReplaceFormat, Marker); + + if (Col != -1 && Row != -1) { + Status = gST->ConOut->SetCursorPosition(gST->ConOut, Col, Row); + } + + FormatWalker = mPostReplaceFormat2; + while (*FormatWalker != CHAR_NULL) { + // + // Find the next attribute change request + // + ResumeLocation = StrStr(FormatWalker, L"%"); + if (ResumeLocation != NULL) { + *ResumeLocation = CHAR_NULL; + } + // + // print the current FormatWalker string + // + if (StrLen(FormatWalker)>0) { + Status = InternalPrintTo(FormatWalker); + if (EFI_ERROR(Status)) { + break; + } + } + + // + // update the attribute + // + if (ResumeLocation != NULL) { + if ((ResumeLocation != mPostReplaceFormat2) && (*(ResumeLocation-1) == L'^')) { + // + // Move cursor back 1 position to overwrite the ^ + // + gST->ConOut->SetCursorPosition(gST->ConOut, gST->ConOut->Mode->CursorColumn - 1, gST->ConOut->Mode->CursorRow); + + // + // Print a simple '%' symbol + // + Status = InternalPrintTo(L"%"); + ResumeLocation = ResumeLocation - 1; + } else { + switch (*(ResumeLocation+1)) { + case (L'N'): + gST->ConOut->SetAttribute(gST->ConOut, OriginalAttribute); + break; + case (L'E'): + gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_YELLOW, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4))); + break; + case (L'H'): + gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_WHITE, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4))); + break; + case (L'B'): + gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_LIGHTBLUE, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4))); + break; + case (L'V'): + gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_LIGHTGREEN, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4))); + break; + default: + // + // Print a simple '%' symbol + // + Status = InternalPrintTo(L"%"); + if (EFI_ERROR(Status)) { + break; + } + ResumeLocation = ResumeLocation - 1; + break; + } + } + } else { + // + // reset to normal now... + // + break; + } + + // + // update FormatWalker to Resume + 2 (skip the % and the indicator) + // + FormatWalker = ResumeLocation + 2; + } + + gST->ConOut->SetAttribute(gST->ConOut, OriginalAttribute); + + SHELL_FREE_NON_NULL(mPostReplaceFormat); + SHELL_FREE_NON_NULL(mPostReplaceFormat2); + return (Status); +} + +/** + Print at a specific location on the screen. + + This function will move the cursor to a given screen location and print the specified string. + + If -1 is specified for either the Row or Col the current screen location for BOTH + will be used. + + If either Row or Col is out of range for the current console, then ASSERT. + If Format is NULL, then ASSERT. + + In addition to the standard %-based flags as supported by UefiLib Print() this supports + the following additional flags: + %N - Set output attribute to normal + %H - Set output attribute to highlight + %E - Set output attribute to error + %B - Set output attribute to blue color + %V - Set output attribute to green color + + Note: The background color is controlled by the shell command cls. + + @param[in] Col the column to print at + @param[in] Row the row to print at + @param[in] Format the format string + @param[in] ... The variable argument list. + + @return EFI_SUCCESS The printing was successful. + @return EFI_DEVICE_ERROR The console device reported an error. +**/ +EFI_STATUS +EFIAPI +ShellPrintEx( + IN INT32 Col OPTIONAL, + IN INT32 Row OPTIONAL, + IN CONST CHAR16 *Format, + ... + ) +{ + VA_LIST Marker; + EFI_STATUS RetVal; + if (Format == NULL) { + return (EFI_INVALID_PARAMETER); + } + VA_START (Marker, Format); + RetVal = InternalShellPrintWorker(Col, Row, Format, Marker); + VA_END(Marker); + return(RetVal); +} + +/** + Print at a specific location on the screen. + + This function will move the cursor to a given screen location and print the specified string. + + If -1 is specified for either the Row or Col the current screen location for BOTH + will be used. + + If either Row or Col is out of range for the current console, then ASSERT. + If Format is NULL, then ASSERT. + + In addition to the standard %-based flags as supported by UefiLib Print() this supports + the following additional flags: + %N - Set output attribute to normal. + %H - Set output attribute to highlight. + %E - Set output attribute to error. + %B - Set output attribute to blue color. + %V - Set output attribute to green color. + + Note: The background color is controlled by the shell command cls. + + @param[in] Col The column to print at. + @param[in] Row The row to print at. + @param[in] Language The language of the string to retrieve. If this parameter + is NULL, then the current platform language is used. + @param[in] HiiFormatStringId The format string Id for getting from Hii. + @param[in] HiiFormatHandle The format string Handle for getting from Hii. + @param[in] ... The variable argument list. + + @return EFI_SUCCESS The printing was successful. + @return EFI_DEVICE_ERROR The console device reported an error. +**/ +EFI_STATUS +EFIAPI +ShellPrintHiiEx( + IN INT32 Col OPTIONAL, + IN INT32 Row OPTIONAL, + IN CONST CHAR8 *Language OPTIONAL, + IN CONST EFI_STRING_ID HiiFormatStringId, + IN CONST EFI_HII_HANDLE HiiFormatHandle, + ... + ) +{ + VA_LIST Marker; + CHAR16 *HiiFormatString; + EFI_STATUS RetVal; + + RetVal = EFI_DEVICE_ERROR; + + VA_START (Marker, HiiFormatHandle); + HiiFormatString = HiiGetString(HiiFormatHandle, HiiFormatStringId, Language); + if (HiiFormatString != NULL) { + RetVal = InternalShellPrintWorker (Col, Row, HiiFormatString, Marker); + SHELL_FREE_NON_NULL (HiiFormatString); + } + VA_END(Marker); + + return (RetVal); +} + +/** + Function to determine if a given filename represents a file or a directory. + + @param[in] DirName Path to directory to test. + + @retval EFI_SUCCESS The Path represents a directory + @retval EFI_NOT_FOUND The Path does not represent a directory + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @return The path failed to open +**/ +EFI_STATUS +EFIAPI +ShellIsDirectory( + IN CONST CHAR16 *DirName + ) +{ + EFI_STATUS Status; + SHELL_FILE_HANDLE Handle; + CHAR16 *TempLocation; + CHAR16 *TempLocation2; + + ASSERT(DirName != NULL); + + Handle = NULL; + TempLocation = NULL; + + Status = ShellOpenFileByName(DirName, &Handle, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR(Status)) { + // + // try good logic first. + // + if (gEfiShellProtocol != NULL) { + TempLocation = StrnCatGrow(&TempLocation, NULL, DirName, 0); + if (TempLocation == NULL) { + ShellCloseFile(&Handle); + return (EFI_OUT_OF_RESOURCES); + } + TempLocation2 = StrStr(TempLocation, L":"); + if (TempLocation2 != NULL && StrLen(StrStr(TempLocation, L":")) == 2) { + *(TempLocation2+1) = CHAR_NULL; + } + if (gEfiShellProtocol->GetDevicePathFromMap(TempLocation) != NULL) { + FreePool(TempLocation); + return (EFI_SUCCESS); + } + FreePool(TempLocation); + } else { + // + // probably a map name?!?!!? + // + TempLocation = StrStr(DirName, L"\\"); + if (TempLocation != NULL && *(TempLocation+1) == CHAR_NULL) { + return (EFI_SUCCESS); + } + } + return (Status); + } + + if (FileHandleIsDirectory(Handle) == EFI_SUCCESS) { + ShellCloseFile(&Handle); + return (EFI_SUCCESS); + } + ShellCloseFile(&Handle); + return (EFI_NOT_FOUND); +} + +/** + Function to determine if a given filename represents a file. + + @param[in] Name Path to file to test. + + @retval EFI_SUCCESS The Path represents a file. + @retval EFI_NOT_FOUND The Path does not represent a file. + @retval other The path failed to open. +**/ +EFI_STATUS +EFIAPI +ShellIsFile( + IN CONST CHAR16 *Name + ) +{ + EFI_STATUS Status; + SHELL_FILE_HANDLE Handle; + + ASSERT(Name != NULL); + + Handle = NULL; + + Status = ShellOpenFileByName(Name, &Handle, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR(Status)) { + return (Status); + } + + if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) { + ShellCloseFile(&Handle); + return (EFI_SUCCESS); + } + ShellCloseFile(&Handle); + return (EFI_NOT_FOUND); +} + +/** + Function to determine if a given filename represents a file. + + This will search the CWD and then the Path. + + If Name is NULL, then ASSERT. + + @param[in] Name Path to file to test. + + @retval EFI_SUCCESS The Path represents a file. + @retval EFI_NOT_FOUND The Path does not represent a file. + @retval other The path failed to open. +**/ +EFI_STATUS +EFIAPI +ShellIsFileInPath( + IN CONST CHAR16 *Name + ) +{ + CHAR16 *NewName; + EFI_STATUS Status; + + if (!EFI_ERROR(ShellIsFile(Name))) { + return (EFI_SUCCESS); + } + + NewName = ShellFindFilePath(Name); + if (NewName == NULL) { + return (EFI_NOT_FOUND); + } + Status = ShellIsFile(NewName); + FreePool(NewName); + return (Status); +} + +/** + Function return the number converted from a hex representation of a number. + + Note: this function cannot be used when (UINTN)(-1), (0xFFFFFFFF) may be a valid + result. Use ShellConvertStringToUint64 instead. + + @param[in] String String representation of a number. + + @return The unsigned integer result of the conversion. + @retval (UINTN)(-1) An error occurred. +**/ +UINTN +EFIAPI +ShellHexStrToUintn( + IN CONST CHAR16 *String + ) +{ + UINT64 RetVal; + + if (!EFI_ERROR(ShellConvertStringToUint64(String, &RetVal, TRUE, TRUE))) { + return ((UINTN)RetVal); + } + + return ((UINTN)(-1)); +} + +/** + Function to determine whether a string is decimal or hex representation of a number + and return the number converted from the string. Spaces are always skipped. + + @param[in] String String representation of a number + + @return the number + @retval (UINTN)(-1) An error ocurred. +**/ +UINTN +EFIAPI +ShellStrToUintn( + IN CONST CHAR16 *String + ) +{ + UINT64 RetVal; + BOOLEAN Hex; + + Hex = FALSE; + + if (!InternalShellIsHexOrDecimalNumber(String, Hex, TRUE, FALSE)) { + Hex = TRUE; + } + + if (!EFI_ERROR(ShellConvertStringToUint64(String, &RetVal, Hex, TRUE))) { + return ((UINTN)RetVal); + } + return ((UINTN)(-1)); +} + +/** + 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 + @param[in] Count Maximum number of characters to append. if 0 then + all are appended. + + @return Destination return the resultant string. +**/ +CHAR16* +EFIAPI +StrnCatGrow ( + IN OUT CHAR16 **Destination, + IN OUT UINTN *CurrentSize, + IN CONST CHAR16 *Source, + IN UINTN Count + ) +{ + UINTN DestinationStartSize; + UINTN NewSize; + + // + // 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; +// ASSERT(*CurrentSize == 0); + } + + // + // Append all of Source? + // + if (Count == 0) { + Count = StrLen(Source); + } + + // + // Test and grow if required + // + if (CurrentSize != NULL) { + NewSize = *CurrentSize; + if (NewSize < DestinationStartSize + (Count * sizeof(CHAR16))) { + while (NewSize < (DestinationStartSize + (Count*sizeof(CHAR16)))) { + NewSize += 2 * Count * sizeof(CHAR16); + } + *Destination = ReallocatePool(*CurrentSize, NewSize, *Destination); + *CurrentSize = NewSize; + } + } else { + NewSize = (Count+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, Count); + return *Destination; +} + +/** + Prompt the user and return the resultant answer to the requestor. + + This function will display the requested question on the shell prompt and then + wait for an appropriate answer to be input from the console. + + if the SHELL_PROMPT_REQUEST_TYPE is SHELL_PROMPT_REQUEST_TYPE_YESNO, ShellPromptResponseTypeQuitContinue + or SHELL_PROMPT_REQUEST_TYPE_YESNOCANCEL then *Response is of type SHELL_PROMPT_RESPONSE. + + if the SHELL_PROMPT_REQUEST_TYPE is ShellPromptResponseTypeFreeform then *Response is of type + CHAR16*. + + In either case *Response must be callee freed if Response was not NULL; + + @param Type What type of question is asked. This is used to filter the input + to prevent invalid answers to question. + @param Prompt Pointer to string prompt to use to request input. + @param Response Pointer to Response which will be populated upon return. + + @retval EFI_SUCCESS The operation was sucessful. + @retval EFI_UNSUPPORTED The operation is not supported as requested. + @retval EFI_INVALID_PARAMETER A parameter was invalid. + @return other The operation failed. +**/ +EFI_STATUS +EFIAPI +ShellPromptForResponse ( + IN SHELL_PROMPT_REQUEST_TYPE Type, + IN CHAR16 *Prompt OPTIONAL, + IN OUT VOID **Response OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_INPUT_KEY Key; + UINTN EventIndex; + SHELL_PROMPT_RESPONSE *Resp; + UINTN Size; + CHAR16 *Buffer; + + Status = EFI_UNSUPPORTED; + Resp = NULL; + Buffer = NULL; + Size = 0; + if (Type != ShellPromptResponseTypeFreeform) { + Resp = (SHELL_PROMPT_RESPONSE*)AllocateZeroPool(sizeof(SHELL_PROMPT_RESPONSE)); + if (Resp == NULL) { + if (Response != NULL) { + *Response = NULL; + } + return (EFI_OUT_OF_RESOURCES); + } + } + + switch(Type) { + case ShellPromptResponseTypeQuitContinue: + if (Prompt != NULL) { + ShellPrintEx(-1, -1, L"%s", Prompt); + } + // + // wait for valid response + // + gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex); + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + if (EFI_ERROR(Status)) { + break; + } + ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar); + if (Key.UnicodeChar == L'Q' || Key.UnicodeChar ==L'q') { + *Resp = ShellPromptResponseQuit; + } else { + *Resp = ShellPromptResponseContinue; + } + break; + case ShellPromptResponseTypeYesNoCancel: + if (Prompt != NULL) { + ShellPrintEx(-1, -1, L"%s", Prompt); + } + // + // wait for valid response + // + *Resp = ShellPromptResponseMax; + while (*Resp == ShellPromptResponseMax) { + if (ShellGetExecutionBreakFlag()) { + Status = EFI_ABORTED; + break; + } + gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex); + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + if (EFI_ERROR(Status)) { + break; + } + ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar); + switch (Key.UnicodeChar) { + case L'Y': + case L'y': + *Resp = ShellPromptResponseYes; + break; + case L'N': + case L'n': + *Resp = ShellPromptResponseNo; + break; + case L'C': + case L'c': + *Resp = ShellPromptResponseCancel; + break; + } + } + break; + case ShellPromptResponseTypeYesNoAllCancel: + if (Prompt != NULL) { + ShellPrintEx(-1, -1, L"%s", Prompt); + } + // + // wait for valid response + // + *Resp = ShellPromptResponseMax; + while (*Resp == ShellPromptResponseMax) { + if (ShellGetExecutionBreakFlag()) { + Status = EFI_ABORTED; + break; + } + gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex); + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + if (EFI_ERROR(Status)) { + break; + } + + if (Key.UnicodeChar <= 127 && Key.UnicodeChar >= 32) { + ShellPrintEx (-1, -1, L"%c", Key.UnicodeChar); + } + + switch (Key.UnicodeChar) { + case L'Y': + case L'y': + *Resp = ShellPromptResponseYes; + break; + case L'N': + case L'n': + *Resp = ShellPromptResponseNo; + break; + case L'A': + case L'a': + *Resp = ShellPromptResponseAll; + break; + case L'C': + case L'c': + *Resp = ShellPromptResponseCancel; + break; + } + } + break; + case ShellPromptResponseTypeEnterContinue: + case ShellPromptResponseTypeAnyKeyContinue: + if (Prompt != NULL) { + ShellPrintEx(-1, -1, L"%s", Prompt); + } + // + // wait for valid response + // + *Resp = ShellPromptResponseMax; + while (*Resp == ShellPromptResponseMax) { + if (ShellGetExecutionBreakFlag()) { + Status = EFI_ABORTED; + break; + } + gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex); + if (Type == ShellPromptResponseTypeEnterContinue) { + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + if (EFI_ERROR(Status)) { + break; + } + ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar); + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { + *Resp = ShellPromptResponseContinue; + break; + } + } + if (Type == ShellPromptResponseTypeAnyKeyContinue) { + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + ASSERT_EFI_ERROR(Status); + *Resp = ShellPromptResponseContinue; + break; + } + } + break; + case ShellPromptResponseTypeYesNo: + if (Prompt != NULL) { + ShellPrintEx(-1, -1, L"%s", Prompt); + } + // + // wait for valid response + // + *Resp = ShellPromptResponseMax; + while (*Resp == ShellPromptResponseMax) { + if (ShellGetExecutionBreakFlag()) { + Status = EFI_ABORTED; + break; + } + gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex); + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + if (EFI_ERROR(Status)) { + break; + } + ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar); + switch (Key.UnicodeChar) { + case L'Y': + case L'y': + *Resp = ShellPromptResponseYes; + break; + case L'N': + case L'n': + *Resp = ShellPromptResponseNo; + break; + } + } + break; + case ShellPromptResponseTypeFreeform: + if (Prompt != NULL) { + ShellPrintEx(-1, -1, L"%s", Prompt); + } + while(1) { + if (ShellGetExecutionBreakFlag()) { + Status = EFI_ABORTED; + break; + } + gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex); + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + if (EFI_ERROR(Status)) { + break; + } + ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar); + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { + break; + } + ASSERT((Buffer == NULL && Size == 0) || (Buffer != NULL)); + StrnCatGrow(&Buffer, &Size, &Key.UnicodeChar, 1); + } + break; + // + // This is the location to add new prompt types. + // If your new type loops remember to add ExecutionBreak support. + // + default: + ASSERT(FALSE); + } + + if (Response != NULL) { + if (Resp != NULL) { + *Response = Resp; + } else if (Buffer != NULL) { + *Response = Buffer; + } else { + *Response = NULL; + } + } else { + if (Resp != NULL) { + FreePool(Resp); + } + if (Buffer != NULL) { + FreePool(Buffer); + } + } + + ShellPrintEx(-1, -1, L"\r\n"); + return (Status); +} + +/** + Prompt the user and return the resultant answer to the requestor. + + This function is the same as ShellPromptForResponse, except that the prompt is + automatically pulled from HII. + + @param Type What type of question is asked. This is used to filter the input + to prevent invalid answers to question. + @param[in] HiiFormatStringId The format string Id for getting from Hii. + @param[in] HiiFormatHandle The format string Handle for getting from Hii. + @param Response Pointer to Response which will be populated upon return. + + @retval EFI_SUCCESS the operation was sucessful. + @return other the operation failed. + + @sa ShellPromptForResponse +**/ +EFI_STATUS +EFIAPI +ShellPromptForResponseHii ( + IN SHELL_PROMPT_REQUEST_TYPE Type, + IN CONST EFI_STRING_ID HiiFormatStringId, + IN CONST EFI_HII_HANDLE HiiFormatHandle, + IN OUT VOID **Response + ) +{ + CHAR16 *Prompt; + EFI_STATUS Status; + + Prompt = HiiGetString(HiiFormatHandle, HiiFormatStringId, NULL); + Status = ShellPromptForResponse(Type, Prompt, Response); + FreePool(Prompt); + return (Status); +} + +/** + Function to determin if an entire string is a valid number. + + If Hex it must be preceeded with a 0x or has ForceHex, set TRUE. + + @param[in] String The string to evaluate. + @param[in] ForceHex TRUE - always assume hex. + @param[in] StopAtSpace TRUE to halt upon finding a space, FALSE to keep going. + @param[in] TimeNumbers TRUE to allow numbers with ":", FALSE otherwise. + + @retval TRUE It is all numeric (dec/hex) characters. + @retval FALSE There is a non-numeric character. +**/ +BOOLEAN +InternalShellIsHexOrDecimalNumber ( + IN CONST CHAR16 *String, + IN CONST BOOLEAN ForceHex, + IN CONST BOOLEAN StopAtSpace, + IN CONST BOOLEAN TimeNumbers + ) +{ + BOOLEAN Hex; + BOOLEAN LeadingZero; + + if (String == NULL) { + return FALSE; + } + + // + // chop off a single negative sign + // + if (*String == L'-') { + String++; + } + + if (*String == CHAR_NULL) { + return FALSE; + } + + // + // chop leading zeroes + // + LeadingZero = FALSE; + while(*String == L'0'){ + String++; + LeadingZero = TRUE; + } + // + // allow '0x' or '0X', but not 'x' or 'X' + // + if (*String == L'x' || *String == L'X') { + if (!LeadingZero) { + // + // we got an x without a preceeding 0 + // + return (FALSE); + } + String++; + Hex = TRUE; + } else if (ForceHex) { + Hex = TRUE; + } else { + Hex = FALSE; + } + + // + // loop through the remaining characters and use the lib function + // + for ( ; *String != CHAR_NULL && !(StopAtSpace && *String == L' ') ; String++){ + if (TimeNumbers && (String[0] == L':')) { + continue; + } + if (Hex) { + if (!ShellIsHexaDecimalDigitCharacter(*String)) { + return (FALSE); + } + } else { + if (!ShellIsDecimalDigitCharacter(*String)) { + return (FALSE); + } + } + } + + return (TRUE); +} + +/** + Function to determine if a given filename exists. + + @param[in] Name Path to test. + + @retval EFI_SUCCESS The Path represents a file. + @retval EFI_NOT_FOUND The Path does not represent a file. + @retval other The path failed to open. +**/ +EFI_STATUS +EFIAPI +ShellFileExists( + IN CONST CHAR16 *Name + ) +{ + EFI_STATUS Status; + EFI_SHELL_FILE_INFO *List; + + ASSERT(Name != NULL); + + List = NULL; + Status = ShellOpenFileMetaArg((CHAR16*)Name, EFI_FILE_MODE_READ, &List); + if (EFI_ERROR(Status)) { + return (Status); + } + + ShellCloseFileMetaArg(&List); + + return (EFI_SUCCESS); +} + +/** + Convert a Unicode character to numerical value. + + This internal function only deal with Unicode character + which maps to a valid hexadecimal ASII character, i.e. + L'0' to L'9', L'a' to L'f' or L'A' to L'F'. For other + Unicode character, the value returned does not make sense. + + @param Char The character to convert. + + @return The numerical value converted. + +**/ +UINTN +InternalShellHexCharToUintn ( + IN CHAR16 Char + ) +{ + if (ShellIsDecimalDigitCharacter (Char)) { + return Char - L'0'; + } + + return (10 + CharToUpper (Char) - L'A'); +} + +/** + Convert a Null-terminated Unicode hexadecimal string to a value of type UINT64. + + This function returns a value of type UINT64 by interpreting the contents + of the Unicode string specified by String as a hexadecimal number. + The format of the input Unicode string String is: + + [spaces][zeros][x][hexadecimal digits]. + + The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F]. + The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix. + If "x" appears in the input string, it must be prefixed with at least one 0. + The function will ignore the pad space, which includes spaces or tab characters, + before [zeros], [x] or [hexadecimal digit]. The running zero before [x] or + [hexadecimal digit] will be ignored. Then, the decoding starts after [x] or the + first valid hexadecimal digit. Then, the function stops at the first character that is + a not a valid hexadecimal character or NULL, whichever one comes first. + + If String has only pad spaces, then zero is returned. + If String has no leading pad spaces, leading zeros or valid hexadecimal digits, + then zero is returned. + + @param[in] String A pointer to a Null-terminated Unicode string. + @param[out] Value Upon a successful return the value of the conversion. + @param[in] StopAtSpace FALSE to skip spaces. + + @retval EFI_SUCCESS The conversion was successful. + @retval EFI_INVALID_PARAMETER A parameter was NULL or invalid. + @retval EFI_DEVICE_ERROR An overflow occurred. +**/ +EFI_STATUS +InternalShellStrHexToUint64 ( + IN CONST CHAR16 *String, + OUT UINT64 *Value, + IN CONST BOOLEAN StopAtSpace + ) +{ + UINT64 Result; + + if (String == NULL || StrSize(String) == 0 || Value == NULL) { + return (EFI_INVALID_PARAMETER); + } + + // + // Ignore the pad spaces (space or tab) + // + while ((*String == L' ') || (*String == L'\t')) { + String++; + } + + // + // Ignore leading Zeros after the spaces + // + while (*String == L'0') { + String++; + } + + if (CharToUpper (*String) == L'X') { + if (*(String - 1) != L'0') { + return 0; + } + // + // Skip the 'X' + // + String++; + } + + Result = 0; + + // + // there is a space where there should't be + // + if (*String == L' ') { + return (EFI_INVALID_PARAMETER); + } + + while (ShellIsHexaDecimalDigitCharacter (*String)) { + // + // If the Hex Number represented by String overflows according + // to the range defined by UINT64, then return EFI_DEVICE_ERROR. + // + if (!(Result <= (RShiftU64((((UINT64) ~0) - InternalShellHexCharToUintn (*String)), 4)))) { +// if (!(Result <= ((((UINT64) ~0) - InternalShellHexCharToUintn (*String)) >> 4))) { + return (EFI_DEVICE_ERROR); + } + + Result = (LShiftU64(Result, 4)); + Result += InternalShellHexCharToUintn (*String); + String++; + + // + // stop at spaces if requested + // + if (StopAtSpace && *String == L' ') { + break; + } + } + + *Value = Result; + return (EFI_SUCCESS); +} + +/** + Convert a Null-terminated Unicode decimal string to a value of + type UINT64. + + This function returns a value of type UINT64 by interpreting the contents + of the Unicode string specified by String as a decimal number. The format + of the input Unicode string String is: + + [spaces] [decimal digits]. + + The valid decimal digit character is in the range [0-9]. The + function will ignore the pad space, which includes spaces or + tab characters, before [decimal digits]. The running zero in the + beginning of [decimal digits] will be ignored. Then, the function + stops at the first character that is a not a valid decimal character + or a Null-terminator, whichever one comes first. + + If String has only pad spaces, then 0 is returned. + If String has no pad spaces or valid decimal digits, + then 0 is returned. + + @param[in] String A pointer to a Null-terminated Unicode string. + @param[out] Value Upon a successful return the value of the conversion. + @param[in] StopAtSpace FALSE to skip spaces. + + @retval EFI_SUCCESS The conversion was successful. + @retval EFI_INVALID_PARAMETER A parameter was NULL or invalid. + @retval EFI_DEVICE_ERROR An overflow occurred. +**/ +EFI_STATUS +InternalShellStrDecimalToUint64 ( + IN CONST CHAR16 *String, + OUT UINT64 *Value, + IN CONST BOOLEAN StopAtSpace + ) +{ + UINT64 Result; + + if (String == NULL || StrSize (String) == 0 || Value == NULL) { + return (EFI_INVALID_PARAMETER); + } + + // + // Ignore the pad spaces (space or tab) + // + while ((*String == L' ') || (*String == L'\t')) { + String++; + } + + // + // Ignore leading Zeros after the spaces + // + while (*String == L'0') { + String++; + } + + Result = 0; + + // + // Stop upon space if requested + // (if the whole value was 0) + // + if (StopAtSpace && *String == L' ') { + *Value = Result; + return (EFI_SUCCESS); + } + + while (ShellIsDecimalDigitCharacter (*String)) { + // + // If the number represented by String overflows according + // to the range defined by UINT64, then return EFI_DEVICE_ERROR. + // + + if (!(Result <= (DivU64x32((((UINT64) ~0) - (*String - L'0')),10)))) { + return (EFI_DEVICE_ERROR); + } + + Result = MultU64x32(Result, 10) + (*String - L'0'); + String++; + + // + // Stop at spaces if requested + // + if (StopAtSpace && *String == L' ') { + break; + } + } + + *Value = Result; + + return (EFI_SUCCESS); +} + +/** + Function to verify and convert a string to its numerical value. + + If Hex it must be preceeded with a 0x, 0X, or has ForceHex set TRUE. + + @param[in] String The string to evaluate. + @param[out] Value Upon a successful return the value of the conversion. + @param[in] ForceHex TRUE - always assume hex. + @param[in] StopAtSpace FALSE to skip spaces. + + @retval EFI_SUCCESS The conversion was successful. + @retval EFI_INVALID_PARAMETER String contained an invalid character. + @retval EFI_NOT_FOUND String was a number, but Value was NULL. +**/ +EFI_STATUS +EFIAPI +ShellConvertStringToUint64( + IN CONST CHAR16 *String, + OUT UINT64 *Value, + IN CONST BOOLEAN ForceHex, + IN CONST BOOLEAN StopAtSpace + ) +{ + UINT64 RetVal; + CONST CHAR16 *Walker; + EFI_STATUS Status; + BOOLEAN Hex; + + Hex = ForceHex; + + if (!InternalShellIsHexOrDecimalNumber(String, Hex, StopAtSpace, FALSE)) { + if (!Hex) { + Hex = TRUE; + if (!InternalShellIsHexOrDecimalNumber(String, Hex, StopAtSpace, FALSE)) { + return (EFI_INVALID_PARAMETER); + } + } else { + return (EFI_INVALID_PARAMETER); + } + } + + // + // Chop off leading spaces + // + for (Walker = String; Walker != NULL && *Walker != CHAR_NULL && *Walker == L' '; Walker++); + + // + // make sure we have something left that is numeric. + // + if (Walker == NULL || *Walker == CHAR_NULL || !InternalShellIsHexOrDecimalNumber(Walker, Hex, StopAtSpace, FALSE)) { + return (EFI_INVALID_PARAMETER); + } + + // + // do the conversion. + // + if (Hex || StrnCmp(Walker, L"0x", 2) == 0 || StrnCmp(Walker, L"0X", 2) == 0){ + Status = InternalShellStrHexToUint64(Walker, &RetVal, StopAtSpace); + } else { + Status = InternalShellStrDecimalToUint64(Walker, &RetVal, StopAtSpace); + } + + if (Value == NULL && !EFI_ERROR(Status)) { + return (EFI_NOT_FOUND); + } + + if (Value != NULL) { + *Value = RetVal; + } + + return (Status); +} + +/** + Function to determin if an entire string is a valid number. + + If Hex it must be preceeded with a 0x or has ForceHex, set TRUE. + + @param[in] String The string to evaluate. + @param[in] ForceHex TRUE - always assume hex. + @param[in] StopAtSpace TRUE to halt upon finding a space, FALSE to keep going. + + @retval TRUE It is all numeric (dec/hex) characters. + @retval FALSE There is a non-numeric character. +**/ +BOOLEAN +EFIAPI +ShellIsHexOrDecimalNumber ( + IN CONST CHAR16 *String, + IN CONST BOOLEAN ForceHex, + IN CONST BOOLEAN StopAtSpace + ) +{ + if (ShellConvertStringToUint64(String, NULL, ForceHex, StopAtSpace) == EFI_NOT_FOUND) { + return (TRUE); + } + return (FALSE); +} + +/** + Function to read a single line from a SHELL_FILE_HANDLE. The \n is not included in the returned + buffer. The returned buffer must be callee freed. + + If the position upon start is 0, then the Ascii Boolean will be set. This should be + maintained and not changed for all operations with the same file. + + @param[in] Handle SHELL_FILE_HANDLE to read from. + @param[in, out] Ascii Boolean value for indicating whether the file is + Ascii (TRUE) or UCS2 (FALSE). + + @return The line of text from the file. + @retval NULL There was not enough memory available. + + @sa ShellFileHandleReadLine +**/ +CHAR16* +EFIAPI +ShellFileHandleReturnLine( + IN SHELL_FILE_HANDLE Handle, + IN OUT BOOLEAN *Ascii + ) +{ + CHAR16 *RetVal; + UINTN Size; + EFI_STATUS Status; + + Size = 0; + RetVal = NULL; + + Status = ShellFileHandleReadLine(Handle, RetVal, &Size, FALSE, Ascii); + if (Status == EFI_BUFFER_TOO_SMALL) { + RetVal = AllocateZeroPool(Size); + if (RetVal == NULL) { + return (NULL); + } + Status = ShellFileHandleReadLine(Handle, RetVal, &Size, FALSE, Ascii); + + } + if (Status == EFI_END_OF_FILE && RetVal != NULL && *RetVal != CHAR_NULL) { + Status = EFI_SUCCESS; + } + if (EFI_ERROR(Status) && (RetVal != NULL)) { + FreePool(RetVal); + RetVal = NULL; + } + return (RetVal); +} + +/** + Function to read a single line (up to but not including the \n) from a SHELL_FILE_HANDLE. + + If the position upon start is 0, then the Ascii Boolean will be set. This should be + maintained and not changed for all operations with the same file. + + NOTE: LINES THAT ARE RETURNED BY THIS FUNCTION ARE UCS2, EVEN IF THE FILE BEING READ + IS IN ASCII FORMAT. + + @param[in] Handle SHELL_FILE_HANDLE to read from. + @param[in, out] Buffer The pointer to buffer to read into. If this function + returns EFI_SUCCESS, then on output Buffer will + contain a UCS2 string, even if the file being + read is ASCII. + @param[in, out] Size On input, pointer to number of bytes in Buffer. + On output, unchanged unless Buffer is too small + to contain the next line of the file. In that + case Size is set to the number of bytes needed + to hold the next line of the file (as a UCS2 + string, even if it is an ASCII file). + @param[in] Truncate If the buffer is large enough, this has no effect. + If the buffer is is too small and Truncate is TRUE, + the line will be truncated. + If the buffer is is too small and Truncate is FALSE, + then no read will occur. + + @param[in, out] Ascii Boolean value for indicating whether the file is + Ascii (TRUE) or UCS2 (FALSE). + + @retval EFI_SUCCESS The operation was successful. The line is stored in + Buffer. + @retval EFI_END_OF_FILE There are no more lines in the file. + @retval EFI_INVALID_PARAMETER Handle was NULL. + @retval EFI_INVALID_PARAMETER Size was NULL. + @retval EFI_BUFFER_TOO_SMALL Size was not large enough to store the line. + Size was updated to the minimum space required. +**/ +EFI_STATUS +EFIAPI +ShellFileHandleReadLine( + IN SHELL_FILE_HANDLE Handle, + IN OUT CHAR16 *Buffer, + IN OUT UINTN *Size, + IN BOOLEAN Truncate, + IN OUT BOOLEAN *Ascii + ) +{ + EFI_STATUS Status; + CHAR16 CharBuffer; + UINTN CharSize; + UINTN CountSoFar; + UINT64 OriginalFilePosition; + + + if (Handle == NULL + ||Size == NULL + ){ + return (EFI_INVALID_PARAMETER); + } + if (Buffer == NULL) { + ASSERT(*Size == 0); + } else { + *Buffer = CHAR_NULL; + } + gEfiShellProtocol->GetFilePosition(Handle, &OriginalFilePosition); + if (OriginalFilePosition == 0) { + CharSize = sizeof(CHAR16); + Status = gEfiShellProtocol->ReadFile(Handle, &CharSize, &CharBuffer); + ASSERT_EFI_ERROR(Status); + if (CharBuffer == gUnicodeFileTag) { + *Ascii = FALSE; + } else { + *Ascii = TRUE; + gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition); + } + } + + if (*Ascii) { + CharSize = sizeof(CHAR8); + } else { + CharSize = sizeof(CHAR16); + } + for (CountSoFar = 0;;CountSoFar++){ + CharBuffer = 0; + Status = gEfiShellProtocol->ReadFile(Handle, &CharSize, &CharBuffer); + if ( EFI_ERROR(Status) + || CharSize == 0 + || (CharBuffer == L'\n' && !(*Ascii)) + || (CharBuffer == '\n' && *Ascii) + ){ + if (CharSize == 0) { + Status = EFI_END_OF_FILE; + } + break; + } + // + // if we have space save it... + // + if ((CountSoFar+1)*sizeof(CHAR16) < *Size){ + ASSERT(Buffer != NULL); + ((CHAR16*)Buffer)[CountSoFar] = CharBuffer; + ((CHAR16*)Buffer)[CountSoFar+1] = CHAR_NULL; + } + } + + // + // if we ran out of space tell when... + // + if ((CountSoFar+1)*sizeof(CHAR16) > *Size){ + *Size = (CountSoFar+1)*sizeof(CHAR16); + if (!Truncate) { + gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition); + } else { + DEBUG((DEBUG_WARN, "The line was truncated in ShellFileHandleReadLine")); + } + return (EFI_BUFFER_TOO_SMALL); + } + while(Buffer[StrLen(Buffer)-1] == L'\r') { + Buffer[StrLen(Buffer)-1] = CHAR_NULL; + } + + return (Status); +} + +/** + Function to print help file / man page content in the spec from the UEFI Shell protocol GetHelpText function. + + @param[in] CommandToGetHelpOn Pointer to a string containing the command name of help file to be printed. + @param[in] SectionToGetHelpOn Pointer to the section specifier(s). + @param[in] PrintCommandText If TRUE, prints the command followed by the help content, otherwise prints + the help content only. + @retval EFI_DEVICE_ERROR The help data format was incorrect. + @retval EFI_NOT_FOUND The help data could not be found. + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +ShellPrintHelp ( + IN CONST CHAR16 *CommandToGetHelpOn, + IN CONST CHAR16 *SectionToGetHelpOn, + IN BOOLEAN PrintCommandText + ) +{ + EFI_STATUS Status; + CHAR16 *OutText; + + OutText = NULL; + + // + // Get the string to print based + // + Status = gEfiShellProtocol->GetHelpText (CommandToGetHelpOn, SectionToGetHelpOn, &OutText); + + // + // make sure we got a valid string + // + if (EFI_ERROR(Status)){ + return Status; + } + if (OutText == NULL || StrLen(OutText) == 0) { + return EFI_NOT_FOUND; + } + + // + // Chop off trailing stuff we dont need + // + while (OutText[StrLen(OutText)-1] == L'\r' || OutText[StrLen(OutText)-1] == L'\n' || OutText[StrLen(OutText)-1] == L' ') { + OutText[StrLen(OutText)-1] = CHAR_NULL; + } + + // + // Print this out to the console + // + if (PrintCommandText) { + ShellPrintEx(-1, -1, L"%H%-14s%N- %s\r\n", CommandToGetHelpOn, OutText); + } else { + ShellPrintEx(-1, -1, L"%N%s\r\n", OutText); + } + + SHELL_FREE_NON_NULL(OutText); + + return EFI_SUCCESS; +} + +/** + Function to delete a file by name + + @param[in] FileName Pointer to file name to delete. + + @retval EFI_SUCCESS the file was deleted sucessfully + @retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not + deleted + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + @retval EFI_NOT_FOUND The specified file could not be found on the + device or the file system could not be found + on the device. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_MEDIA_CHANGED The device has a different medium in it or the + medium is no longer supported. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The file or medium is write protected. + @retval EFI_ACCESS_DENIED The file was opened read only. + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the + file. + @retval other The file failed to open +**/ +EFI_STATUS +EFIAPI +ShellDeleteFileByName( + IN CONST CHAR16 *FileName + ) +{ + EFI_STATUS Status; + SHELL_FILE_HANDLE FileHandle; + + Status = ShellFileExists(FileName); + + if (Status == EFI_SUCCESS){ + Status = ShellOpenFileByName(FileName, &FileHandle, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0x0); + if (Status == EFI_SUCCESS){ + Status = ShellDeleteFile(&FileHandle); + } + } + + return(Status); + +} + +/** + Cleans off all the quotes in the string. + + @param[in] OriginalString pointer to the string to be cleaned. + @param[out] CleanString The new string with all quotes removed. + Memory allocated in the function and free + by caller. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +InternalShellStripQuotes ( + IN CONST CHAR16 *OriginalString, + OUT CHAR16 **CleanString + ) +{ + CHAR16 *Walker; + + if (OriginalString == NULL || CleanString == NULL) { + return EFI_INVALID_PARAMETER; + } + + *CleanString = AllocateCopyPool (StrSize (OriginalString), OriginalString); + if (*CleanString == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + for (Walker = *CleanString; Walker != NULL && *Walker != CHAR_NULL ; Walker++) { + if (*Walker == L'\"') { + CopyMem(Walker, Walker+1, StrSize(Walker) - sizeof(Walker[0])); + } + } + + return EFI_SUCCESS; +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLib/UefiShellLib.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLib/UefiShellLib.h new file mode 100644 index 00000000..f12dfee6 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLib/UefiShellLib.h @@ -0,0 +1,90 @@ +/** @file + Provides interface to shell functionality for shell commands and applications. + + (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _UEFI_SHELL_LIB_INTERNAL_H_ +#define _UEFI_SHELL_LIB_INTERNAL_H_ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + EFI_SHELL_GET_FILE_INFO GetFileInfo; + EFI_SHELL_SET_FILE_INFO SetFileInfo; + EFI_SHELL_READ_FILE ReadFile; + EFI_SHELL_WRITE_FILE WriteFile; + EFI_SHELL_CLOSE_FILE CloseFile; + EFI_SHELL_DELETE_FILE DeleteFile; + EFI_SHELL_GET_FILE_POSITION GetFilePosition; + EFI_SHELL_SET_FILE_POSITION SetFilePosition; + EFI_SHELL_FLUSH_FILE FlushFile; + EFI_SHELL_GET_FILE_SIZE GetFileSize; +} FILE_HANDLE_FUNCTION_MAP; + +/** + Function to determin if an entire string is a valid number. + + If Hex it must be preceeded with a 0x or has ForceHex, set TRUE. + + @param[in] String The string to evaluate. + @param[in] ForceHex TRUE - always assume hex. + @param[in] StopAtSpace TRUE to halt upon finding a space, FALSE to keep going. + @param[in] TimeNumbers TRUE to allow numbers with ":", FALSE otherwise. + + @retval TRUE It is all numeric (dec/hex) characters. + @retval FALSE There is a non-numeric character. +**/ +BOOLEAN +InternalShellIsHexOrDecimalNumber ( + IN CONST CHAR16 *String, + IN CONST BOOLEAN ForceHex, + IN CONST BOOLEAN StopAtSpace, + IN CONST BOOLEAN TimeNumbers + ); + +/** + Cleans off all the quotes in the string. + + @param[in] OriginalString pointer to the string to be cleaned. + @param[out] CleanString The new string with all quotes removed. + Memory allocated in the function and free + by caller. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +InternalShellStripQuotes ( + IN CONST CHAR16 *OriginalString, + OUT CHAR16 **CleanString + ); + + +#endif + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLib/UefiShellLib.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLib/UefiShellLib.inf new file mode 100644 index 00000000..aff2d36d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellLib/UefiShellLib.inf @@ -0,0 +1,65 @@ +## @file +# Provides interface to shell functionality for shell commands and applications. +# +# (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiShellLib + FILE_GUID = 449D0F00-2148-4a43-9836-F10B3980ECF5 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.2 + LIBRARY_CLASS = ShellLib|UEFI_APPLICATION UEFI_DRIVER DXE_RUNTIME_DRIVER DXE_DRIVER + CONSTRUCTOR = ShellLibConstructor + DESTRUCTOR = ShellLibDestructor + +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources.common] + UefiShellLib.c + UefiShellLib.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + ShellPkg/ShellPkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + MemoryAllocationLib + DevicePathLib + BaseLib + BaseMemoryLib + DebugLib + FileHandleLib + PrintLib + UefiLib + HiiLib + SortLib + +[Protocols] + gEfiUnicodeCollation2ProtocolGuid ## CONSUMES + + # shell 2.0 + gEfiShellProtocolGuid ## SOMETIMES_CONSUMES + gEfiShellParametersProtocolGuid ## SOMETIMES_CONSUMES + + # 'old' shell + gEfiShellEnvironment2Guid ## SOMETIMES_CONSUMES + gEfiShellInterfaceGuid ## SOMETIMES_CONSUMES + +[Guids] + gEfiFileInfoGuid ## SOMETIMES_CONSUMES ## GUID + gEfiShellEnvironment2ExtGuid ## SOMETIMES_CONSUMES ## GUID + +[Pcd.common] + gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize ## CONSUMES + gEfiShellPkgTokenSpaceGuid.PcdShellPrintBufferSize ## CONSUMES diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ifconfig.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ifconfig.c new file mode 100644 index 00000000..26587913 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ifconfig.c @@ -0,0 +1,1441 @@ +/** @file + The implementation for Shell command ifconfig based on IP4Config2 protocol. + + (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellNetwork1CommandsLib.h" + +typedef enum { + IfConfigOpList = 1, + IfConfigOpSet = 2, + IfConfigOpClear = 3 +} IFCONFIG_OPCODE; + +typedef enum { + VarCheckReserved = -1, + VarCheckOk = 0, + VarCheckDuplicate, + VarCheckConflict, + VarCheckUnknown, + VarCheckLackValue, + VarCheckOutOfMem +} VAR_CHECK_CODE; + +typedef enum { + FlagTypeSingle = 0, + FlagTypeNeedVar, + FlagTypeNeedSet, + FlagTypeSkipUnknown +} VAR_CHECK_FLAG_TYPE; + +#define MACADDRMAXSIZE 32 + +typedef struct _IFCONFIG_INTERFACE_CB { + EFI_HANDLE NicHandle; + LIST_ENTRY Link; + EFI_IP4_CONFIG2_PROTOCOL *IfCfg; + EFI_IP4_CONFIG2_INTERFACE_INFO *IfInfo; + EFI_IP4_CONFIG2_POLICY Policy; + UINT32 DnsCnt; + EFI_IPv4_ADDRESS DnsAddr[1]; +} IFCONFIG_INTERFACE_CB; + +typedef struct _ARG_LIST ARG_LIST; + +struct _ARG_LIST { + ARG_LIST *Next; + CHAR16 *Arg; +}; + +typedef struct _IFCONFIG4_PRIVATE_DATA { + LIST_ENTRY IfList; + + UINT32 OpCode; + CHAR16 *IfName; + ARG_LIST *VarArg; +} IFCONFIG_PRIVATE_DATA; + +typedef struct _VAR_CHECK_ITEM{ + CHAR16 *FlagStr; + UINT32 FlagID; + UINT32 ConflictMask; + VAR_CHECK_FLAG_TYPE FlagType; +} VAR_CHECK_ITEM; + +SHELL_PARAM_ITEM mIfConfigCheckList[] = { + { + L"-b", + TypeFlag + }, + { + L"-l", + TypeValue + }, + { + L"-r", + TypeValue + }, + { + L"-c", + TypeValue + }, + { + L"-s", + TypeMaxValue + }, + { + NULL, + TypeMax + }, +}; + +VAR_CHECK_ITEM mSetCheckList[] = { + { + L"static", + 0x00000001, + 0x00000001, + FlagTypeSingle + }, + { + L"dhcp", + 0x00000002, + 0x00000001, + FlagTypeSingle + }, + { + L"dns", + 0x00000008, + 0x00000004, + FlagTypeSingle + }, + { + NULL, + 0x0, + 0x0, + FlagTypeSkipUnknown + }, +}; + +STATIC CONST CHAR16 PermanentString[10] = L"PERMANENT"; + +/** + Free the ARG_LIST. + + @param List Pointer to ARG_LIST to free. +**/ +VOID +FreeArgList ( + ARG_LIST *List +) +{ + ARG_LIST *Next; + while (List->Next != NULL) { + Next = List->Next; + FreePool (List); + List = Next; + } + + FreePool (List); +} + +/** + Split a string with specified separator and save the substring to a list. + + @param[in] String The pointer of the input string. + @param[in] Separator The specified separator. + + @return The pointer of headnode of ARG_LIST. + +**/ +ARG_LIST * +SplitStrToList ( + IN CONST CHAR16 *String, + IN CHAR16 Separator + ) +{ + CHAR16 *Str; + CHAR16 *ArgStr; + ARG_LIST *ArgList; + ARG_LIST *ArgNode; + + if (*String == L'\0') { + return NULL; + } + + // + // Copy the CONST string to a local copy. + // + Str = AllocateCopyPool (StrSize (String), String); + if (Str == NULL) { + return NULL; + } + ArgStr = Str; + + // + // init a node for the list head. + // + ArgNode = (ARG_LIST *) AllocateZeroPool (sizeof (ARG_LIST)); + if (ArgNode == NULL) { + return NULL; + } + ArgList = ArgNode; + + // + // Split the local copy and save in the list node. + // + while (*Str != L'\0') { + if (*Str == Separator) { + *Str = L'\0'; + ArgNode->Arg = ArgStr; + ArgStr = Str + 1; + ArgNode->Next = (ARG_LIST *) AllocateZeroPool (sizeof (ARG_LIST)); + if (ArgNode->Next == NULL) { + // + // Free the local copy of string stored in the first node + // + FreePool (ArgList->Arg); + FreeArgList (ArgList); + return NULL; + } + ArgNode = ArgNode->Next; + } + + Str++; + } + + ArgNode->Arg = ArgStr; + ArgNode->Next = NULL; + + return ArgList; +} + +/** + Check the correctness of input Args with '-s' option. + + @param[in] CheckList The pointer of VAR_CHECK_ITEM array. + @param[in] Name The pointer of input arg. + @param[in] Init The switch to execute the check. + + @return VarCheckOk Valid parameter or Initialize check successfully. + @return VarCheckDuplicate Duplicated parameter happened. + @return VarCheckConflict Conflicted parameter happened + @return VarCheckUnknown Unknown parameter. + +**/ +VAR_CHECK_CODE +IfConfigRetriveCheckListByName( + IN VAR_CHECK_ITEM *CheckList, + IN CHAR16 *Name, + IN BOOLEAN Init +) +{ + STATIC UINT32 CheckDuplicate; + STATIC UINT32 CheckConflict; + VAR_CHECK_CODE RtCode; + UINT32 Index; + VAR_CHECK_ITEM Arg; + + if (Init) { + CheckDuplicate = 0; + CheckConflict = 0; + return VarCheckOk; + } + + RtCode = VarCheckOk; + Index = 0; + Arg = CheckList[Index]; + + // + // Check the Duplicated/Conflicted/Unknown input Args. + // + while (Arg.FlagStr != NULL) { + if (StrCmp (Arg.FlagStr, Name) == 0) { + + if (CheckDuplicate & Arg.FlagID) { + RtCode = VarCheckDuplicate; + break; + } + + if (CheckConflict & Arg.ConflictMask) { + RtCode = VarCheckConflict; + break; + } + + CheckDuplicate |= Arg.FlagID; + CheckConflict |= Arg.ConflictMask; + break; + } + + Arg = CheckList[++Index]; + } + + if (Arg.FlagStr == NULL) { + RtCode = VarCheckUnknown; + } + + return RtCode; +} + +/** + The notify function of create event when performing a manual config. + + @param[in] Event The event this notify function registered to. + @param[in] Context Pointer to the context data registered to the event. + +**/ +VOID +EFIAPI +IfConfigManualAddressNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + *((BOOLEAN *) Context) = TRUE; +} + +/** + Print MAC address. + + @param[in] Node The pointer of MAC address buffer. + @param[in] Size The size of MAC address buffer. + +**/ +VOID +IfConfigPrintMacAddr ( + IN UINT8 *Node, + IN UINT32 Size + ) +{ + UINTN Index; + + ASSERT (Size <= MACADDRMAXSIZE); + + for (Index = 0; Index < Size; Index++) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_MAC_ADDR_BODY), gShellNetwork1HiiHandle, Node[Index]); + if (Index + 1 < Size) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_COLON), gShellNetwork1HiiHandle); + } + } + + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_NEWLINE), gShellNetwork1HiiHandle); +} + + +/** + The get current status of all handles. + + @param[in] IfName The pointer of IfName(interface name). + @param[in] IfList The pointer of IfList(interface list). + + @retval EFI_SUCCESS The get status processed successfully. + @retval others The get status process failed. + +**/ +EFI_STATUS +IfConfigGetInterfaceInfo ( + IN CHAR16 *IfName, + IN LIST_ENTRY *IfList + ) +{ + EFI_STATUS Status; + UINTN HandleIndex; + UINTN HandleNum; + EFI_HANDLE *HandleBuffer; + EFI_IP4_CONFIG2_PROTOCOL *Ip4Cfg2; + EFI_IP4_CONFIG2_INTERFACE_INFO *IfInfo; + IFCONFIG_INTERFACE_CB *IfCb; + UINTN DataSize; + + HandleBuffer = NULL; + HandleNum = 0; + + IfInfo = NULL; + IfCb = NULL; + + // + // Locate all the handles with ip4 service binding protocol. + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiIp4ServiceBindingProtocolGuid, + NULL, + &HandleNum, + &HandleBuffer + ); + if (EFI_ERROR (Status) || (HandleNum == 0)) { + return Status; + } + + // + // Enumerate all handles that installed with ip4 service binding protocol. + // + for (HandleIndex = 0; HandleIndex < HandleNum; HandleIndex++) { + IfCb = NULL; + IfInfo = NULL; + DataSize = 0; + + // + // Ip4config protocol and ip4 service binding protocol are installed + // on the same handle. + // + ASSERT (HandleBuffer != NULL); + Status = gBS->HandleProtocol ( + HandleBuffer[HandleIndex], + &gEfiIp4Config2ProtocolGuid, + (VOID **) &Ip4Cfg2 + ); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Get the interface information size. + // + Status = Ip4Cfg2->GetData ( + Ip4Cfg2, + Ip4Config2DataTypeInterfaceInfo, + &DataSize, + NULL + ); + + if (Status != EFI_BUFFER_TOO_SMALL) { + goto ON_ERROR; + } + + IfInfo = AllocateZeroPool (DataSize); + + if (IfInfo == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + + // + // Get the interface info. + // + Status = Ip4Cfg2->GetData ( + Ip4Cfg2, + Ip4Config2DataTypeInterfaceInfo, + &DataSize, + IfInfo + ); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Check the interface name if required. + // + if ((IfName != NULL) && (StrCmp (IfName, IfInfo->Name) != 0)) { + FreePool (IfInfo); + continue; + } + + DataSize = 0; + + // + // Get the size of dns server list. + // + Status = Ip4Cfg2->GetData ( + Ip4Cfg2, + Ip4Config2DataTypeDnsServer, + &DataSize, + NULL + ); + + if ((Status != EFI_BUFFER_TOO_SMALL) && (Status != EFI_NOT_FOUND)) { + goto ON_ERROR; + } + + IfCb = AllocateZeroPool (sizeof (IFCONFIG_INTERFACE_CB) + DataSize); + + if (IfCb == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + + IfCb->NicHandle = HandleBuffer[HandleIndex]; + IfCb->IfInfo = IfInfo; + IfCb->IfCfg = Ip4Cfg2; + IfCb->DnsCnt = (UINT32) (DataSize / sizeof (EFI_IPv4_ADDRESS)); + + // + // Get the dns server list if has. + // + if (DataSize > 0) { + Status = Ip4Cfg2->GetData ( + Ip4Cfg2, + Ip4Config2DataTypeDnsServer, + &DataSize, + IfCb->DnsAddr + ); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + } + + // + // Get the config policy. + // + DataSize = sizeof (EFI_IP4_CONFIG2_POLICY); + Status = Ip4Cfg2->GetData ( + Ip4Cfg2, + Ip4Config2DataTypePolicy, + &DataSize, + &IfCb->Policy + ); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + InsertTailList (IfList, &IfCb->Link); + + if ((IfName != NULL) && (StrCmp (IfName, IfInfo->Name) == 0)) { + // + // Only need the appointed interface, keep the allocated buffer. + // + IfCb = NULL; + IfInfo = NULL; + break; + } + } + + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + + return EFI_SUCCESS; + +ON_ERROR: + + if (IfInfo != NULL) { + FreePool (IfInfo); + } + + if (IfCb != NULL) { + FreePool (IfCb); + } + + return Status; +} + +/** + The list process of the ifconfig command. + + @param[in] IfList The pointer of IfList(interface list). + + @retval SHELL_SUCCESS The ifconfig command list processed successfully. + @retval others The ifconfig command list process failed. + +**/ +SHELL_STATUS +IfConfigShowInterfaceInfo ( + IN LIST_ENTRY *IfList + ) +{ + LIST_ENTRY *Entry; + LIST_ENTRY *Next; + IFCONFIG_INTERFACE_CB *IfCb; + EFI_STATUS MediaStatus; + EFI_IPv4_ADDRESS Gateway; + UINT32 Index; + + MediaStatus = EFI_SUCCESS; + + if (IsListEmpty (IfList)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INVALID_INTERFACE), gShellNetwork1HiiHandle); + } + + // + // Go through the interface list. + // + NET_LIST_FOR_EACH_SAFE (Entry, Next, IfList) { + IfCb = NET_LIST_USER_STRUCT (Entry, IFCONFIG_INTERFACE_CB, Link); + + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_BREAK), gShellNetwork1HiiHandle); + + // + // Print interface name. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_IF_NAME), gShellNetwork1HiiHandle, IfCb->IfInfo->Name); + + // + // Get Media State. + // + if (EFI_SUCCESS == NetLibDetectMediaWaitTimeout (IfCb->NicHandle, 0, &MediaStatus)) { + if (MediaStatus != EFI_SUCCESS) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_MEDIA_STATE), gShellNetwork1HiiHandle, L"Media disconnected"); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_MEDIA_STATE), gShellNetwork1HiiHandle, L"Media present"); + } + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_MEDIA_STATE), gShellNetwork1HiiHandle, L"Media state unknown"); + } + + // + // Print interface config policy. + // + if (IfCb->Policy == Ip4Config2PolicyDhcp) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_POLICY_DHCP), gShellNetwork1HiiHandle); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_POLICY_MAN), gShellNetwork1HiiHandle); + } + + // + // Print mac address of the interface. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_MAC_ADDR_HEAD), gShellNetwork1HiiHandle); + + IfConfigPrintMacAddr ( + IfCb->IfInfo->HwAddress.Addr, + IfCb->IfInfo->HwAddressSize + ); + + // + // Print IPv4 address list of the interface. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_IP_ADDR_HEAD), gShellNetwork1HiiHandle); + + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_IFCONFIG_INFO_IP_ADDR_BODY), + gShellNetwork1HiiHandle, + (UINTN)IfCb->IfInfo->StationAddress.Addr[0], + (UINTN)IfCb->IfInfo->StationAddress.Addr[1], + (UINTN)IfCb->IfInfo->StationAddress.Addr[2], + (UINTN)IfCb->IfInfo->StationAddress.Addr[3] + ); + + // + // Print subnet mask list of the interface. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_SUBNET_MASK_HEAD), gShellNetwork1HiiHandle); + + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_IFCONFIG_INFO_IP_ADDR_BODY), + gShellNetwork1HiiHandle, + (UINTN)IfCb->IfInfo->SubnetMask.Addr[0], + (UINTN)IfCb->IfInfo->SubnetMask.Addr[1], + (UINTN)IfCb->IfInfo->SubnetMask.Addr[2], + (UINTN)IfCb->IfInfo->SubnetMask.Addr[3] + ); + + // + // Print default gateway of the interface. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_GATEWAY_HEAD), gShellNetwork1HiiHandle); + + ZeroMem (&Gateway, sizeof (EFI_IPv4_ADDRESS)); + + for (Index = 0; Index < IfCb->IfInfo->RouteTableSize; Index++) { + if ((CompareMem (&IfCb->IfInfo->RouteTable[Index].SubnetAddress, &mZeroIp4Addr, sizeof (EFI_IPv4_ADDRESS)) == 0) && + (CompareMem (&IfCb->IfInfo->RouteTable[Index].SubnetMask , &mZeroIp4Addr, sizeof (EFI_IPv4_ADDRESS)) == 0) ){ + CopyMem (&Gateway, &IfCb->IfInfo->RouteTable[Index].GatewayAddress, sizeof (EFI_IPv4_ADDRESS)); + } + } + + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_IFCONFIG_INFO_IP_ADDR_BODY), + gShellNetwork1HiiHandle, + (UINTN)Gateway.Addr[0], + (UINTN)Gateway.Addr[1], + (UINTN)Gateway.Addr[2], + (UINTN)Gateway.Addr[3] + ); + + // + // Print route table entry. + // + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_ROUTES_SIZE), gShellNetwork1HiiHandle, IfCb->IfInfo->RouteTableSize); + + for (Index = 0; Index < IfCb->IfInfo->RouteTableSize; Index++) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_ROUTES_ENTRY_INDEX), gShellNetwork1HiiHandle, Index); + + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR), + gShellNetwork1HiiHandle, + L"Subnet ", + (UINTN)IfCb->IfInfo->RouteTable[Index].SubnetAddress.Addr[0], + (UINTN)IfCb->IfInfo->RouteTable[Index].SubnetAddress.Addr[1], + (UINTN)IfCb->IfInfo->RouteTable[Index].SubnetAddress.Addr[2], + (UINTN)IfCb->IfInfo->RouteTable[Index].SubnetAddress.Addr[3] + ); + + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR), + gShellNetwork1HiiHandle, + L"Netmask", + (UINTN)IfCb->IfInfo->RouteTable[Index].SubnetMask.Addr[0], + (UINTN)IfCb->IfInfo->RouteTable[Index].SubnetMask.Addr[1], + (UINTN)IfCb->IfInfo->RouteTable[Index].SubnetMask.Addr[2], + (UINTN)IfCb->IfInfo->RouteTable[Index].SubnetMask.Addr[3] + ); + + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR), + gShellNetwork1HiiHandle, + L"Gateway", + (UINTN)IfCb->IfInfo->RouteTable[Index].GatewayAddress.Addr[0], + (UINTN)IfCb->IfInfo->RouteTable[Index].GatewayAddress.Addr[1], + (UINTN)IfCb->IfInfo->RouteTable[Index].GatewayAddress.Addr[2], + (UINTN)IfCb->IfInfo->RouteTable[Index].GatewayAddress.Addr[3] + ); + } + + // + // Print dns server addresses list of the interface if has. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_DNS_ADDR_HEAD), gShellNetwork1HiiHandle); + + for (Index = 0; Index < IfCb->DnsCnt; Index++) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_IFCONFIG_INFO_DNS_ADDR_BODY), + gShellNetwork1HiiHandle, + (UINTN) IfCb->DnsAddr[Index].Addr[0], + (UINTN) IfCb->DnsAddr[Index].Addr[1], + (UINTN) IfCb->DnsAddr[Index].Addr[2], + (UINTN) IfCb->DnsAddr[Index].Addr[3] + ); + + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_NEWLINE), gShellNetwork1HiiHandle); + } + } + + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_BREAK), gShellNetwork1HiiHandle); + + return SHELL_SUCCESS; +} + +/** + The clean process of the ifconfig command to clear interface info. + + @param[in] IfList The pointer of IfList(interface list). + @param[in] IfName The pointer of interface name. + + @retval SHELL_SUCCESS The ifconfig command clean processed successfully. + @retval others The ifconfig command clean process failed. + +**/ +SHELL_STATUS +IfConfigClearInterfaceInfo ( + IN LIST_ENTRY *IfList, + IN CHAR16 *IfName + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + LIST_ENTRY *Entry; + LIST_ENTRY *Next; + IFCONFIG_INTERFACE_CB *IfCb; + EFI_IP4_CONFIG2_POLICY Policy; + + Status = EFI_SUCCESS; + ShellStatus = SHELL_SUCCESS; + + if (IsListEmpty (IfList)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INVALID_INTERFACE), gShellNetwork1HiiHandle); + } + + // + // Go through the interface list. + // If the interface name is specified, DHCP DORA process will be + // triggered by the policy transition (static -> dhcp). + // + NET_LIST_FOR_EACH_SAFE (Entry, Next, IfList) { + IfCb = NET_LIST_USER_STRUCT (Entry, IFCONFIG_INTERFACE_CB, Link); + + if ((IfName != NULL) && (StrCmp (IfName, IfCb->IfInfo->Name) == 0)) { + Policy = Ip4Config2PolicyStatic; + + Status = IfCb->IfCfg->SetData ( + IfCb->IfCfg, + Ip4Config2DataTypePolicy, + sizeof (EFI_IP4_CONFIG2_POLICY), + &Policy + ); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellNetwork1HiiHandle, L"ifconfig"); + ShellStatus = SHELL_ACCESS_DENIED; + break; + } + } + + Policy = Ip4Config2PolicyDhcp; + + Status = IfCb->IfCfg->SetData ( + IfCb->IfCfg, + Ip4Config2DataTypePolicy, + sizeof (EFI_IP4_CONFIG2_POLICY), + &Policy + ); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellNetwork1HiiHandle, L"ifconfig"); + ShellStatus = SHELL_ACCESS_DENIED; + break; + } + } + + return ShellStatus; +} + +/** + The set process of the ifconfig command. + + @param[in] IfList The pointer of IfList(interface list). + @param[in] VarArg The pointer of ARG_LIST(Args with "-s" option). + + @retval SHELL_SUCCESS The ifconfig command set processed successfully. + @retval others The ifconfig command set process failed. + +**/ +SHELL_STATUS +IfConfigSetInterfaceInfo ( + IN LIST_ENTRY *IfList, + IN ARG_LIST *VarArg + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + IFCONFIG_INTERFACE_CB *IfCb; + VAR_CHECK_CODE CheckCode; + EFI_EVENT TimeOutEvt; + EFI_EVENT MappedEvt; + BOOLEAN IsAddressOk; + + EFI_IP4_CONFIG2_POLICY Policy; + EFI_IP4_CONFIG2_MANUAL_ADDRESS ManualAddress; + UINTN DataSize; + EFI_IPv4_ADDRESS Gateway; + IP4_ADDR SubnetMask; + IP4_ADDR TempGateway; + EFI_IPv4_ADDRESS *Dns; + ARG_LIST *Tmp; + UINTN Index; + + CONST CHAR16* TempString; + + Dns = NULL; + + if (IsListEmpty (IfList)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INVALID_INTERFACE), gShellNetwork1HiiHandle); + return SHELL_INVALID_PARAMETER; + } + + // + // Make sure to set only one interface each time. + // + IfCb = NET_LIST_USER_STRUCT (IfList->ForwardLink, IFCONFIG_INTERFACE_CB, Link); + Status = EFI_SUCCESS; + ShellStatus = SHELL_SUCCESS; + + // + // Initialize check list mechanism. + // + CheckCode = IfConfigRetriveCheckListByName( + NULL, + NULL, + TRUE + ); + + // + // Create events & timers for asynchronous settings. + // + Status = gBS->CreateEvent ( + EVT_TIMER, + TPL_CALLBACK, + NULL, + NULL, + &TimeOutEvt + ); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellNetwork1HiiHandle, L"ifconfig"); + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + IfConfigManualAddressNotify, + &IsAddressOk, + &MappedEvt + ); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellNetwork1HiiHandle, L"ifconfig"); + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + // + // Parse the setting variables. + // + while (VarArg != NULL) { + // + // Check invalid parameters (duplication & unknown & conflict). + // + CheckCode = IfConfigRetriveCheckListByName( + mSetCheckList, + VarArg->Arg, + FALSE + ); + + if (VarCheckOk != CheckCode) { + switch (CheckCode) { + case VarCheckDuplicate: + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_DUPLICATE_COMMAND), gShellNetwork1HiiHandle, VarArg->Arg); + break; + + case VarCheckConflict: + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_CONFLICT_COMMAND), gShellNetwork1HiiHandle, VarArg->Arg); + break; + + case VarCheckUnknown: + // + // To handle unsupported option. + // + TempString = PermanentString; + if (StringNoCaseCompare(&VarArg->Arg, &TempString) == 0) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_UNSUPPORTED_OPTION), gShellNetwork1HiiHandle, PermanentString); + goto ON_EXIT; + } + + // + // To handle unknown option. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_UNKNOWN_COMMAND), gShellNetwork1HiiHandle, VarArg->Arg); + break; + + default: + break; + } + + VarArg = VarArg->Next; + continue; + } + + // + // Process valid variables. + // + if (StrCmp(VarArg->Arg, L"dhcp") == 0) { + // + // Set dhcp config policy + // + Policy = Ip4Config2PolicyDhcp; + Status = IfCb->IfCfg->SetData ( + IfCb->IfCfg, + Ip4Config2DataTypePolicy, + sizeof (EFI_IP4_CONFIG2_POLICY), + &Policy + ); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellNetwork1HiiHandle, L"ifconfig"); + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + VarArg= VarArg->Next; + + } else if (StrCmp (VarArg->Arg, L"static") == 0) { + VarArg= VarArg->Next; + if (VarArg == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_LACK_COMMAND), gShellNetwork1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + + ZeroMem (&ManualAddress, sizeof (ManualAddress)); + + // + // Get manual IP address. + // + Status = NetLibStrToIp4 (VarArg->Arg, &ManualAddress.Address); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_INVALID_IPADDRESS), gShellNetwork1HiiHandle, VarArg->Arg); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + + // + // Get subnetmask. + // + VarArg = VarArg->Next; + if (VarArg == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_LACK_COMMAND), gShellNetwork1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + + Status = NetLibStrToIp4 (VarArg->Arg, &ManualAddress.SubnetMask); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_INVALID_IPADDRESS), gShellNetwork1HiiHandle, VarArg->Arg); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + + // + // Get gateway. + // + VarArg = VarArg->Next; + if (VarArg == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_LACK_COMMAND), gShellNetwork1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + + Status = NetLibStrToIp4 (VarArg->Arg, &Gateway); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_INVALID_IPADDRESS), gShellNetwork1HiiHandle, VarArg->Arg); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + + // + // Need to check the gateway validity before set Manual Address. + // In case we can set manual address but fail to configure Gateway. + // + CopyMem (&SubnetMask, &ManualAddress.SubnetMask, sizeof (IP4_ADDR)); + CopyMem (&TempGateway, &Gateway, sizeof (IP4_ADDR)); + SubnetMask = NTOHL (SubnetMask); + TempGateway = NTOHL (TempGateway); + if ((SubnetMask != 0) && + (SubnetMask != 0xFFFFFFFFu) && + !NetIp4IsUnicast (TempGateway, SubnetMask)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INVALID_GATEWAY), gShellNetwork1HiiHandle, VarArg->Arg); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + + // + // Set manual config policy. + // + Policy = Ip4Config2PolicyStatic; + Status = IfCb->IfCfg->SetData ( + IfCb->IfCfg, + Ip4Config2DataTypePolicy, + sizeof (EFI_IP4_CONFIG2_POLICY), + &Policy + ); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellNetwork1HiiHandle, L"ifconfig"); + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + // + // Set Manual Address. + // + IsAddressOk = FALSE; + + Status = IfCb->IfCfg->RegisterDataNotify ( + IfCb->IfCfg, + Ip4Config2DataTypeManualAddress, + MappedEvt + ); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_SET_ADDR_FAILED), gShellNetwork1HiiHandle, Status); + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + DataSize = sizeof (EFI_IP4_CONFIG2_MANUAL_ADDRESS); + + Status = IfCb->IfCfg->SetData ( + IfCb->IfCfg, + Ip4Config2DataTypeManualAddress, + DataSize, + &ManualAddress + ); + + if (Status == EFI_NOT_READY) { + gBS->SetTimer (TimeOutEvt, TimerRelative, 50000000); + + while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) { + if (IsAddressOk) { + Status = EFI_SUCCESS; + break; + } + } + } + + IfCb->IfCfg->UnregisterDataNotify ( + IfCb->IfCfg, + Ip4Config2DataTypeManualAddress, + MappedEvt + ); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_SET_ADDR_FAILED), gShellNetwork1HiiHandle, Status); + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + // + // Set gateway. + // + DataSize = sizeof (EFI_IPv4_ADDRESS); + + Status = IfCb->IfCfg->SetData ( + IfCb->IfCfg, + Ip4Config2DataTypeGateway, + DataSize, + &Gateway + ); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_SET_ADDR_FAILED), gShellNetwork1HiiHandle, Status); + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + VarArg = VarArg->Next; + + } else if (StrCmp (VarArg->Arg, L"dns") == 0) { + // + // Get DNS addresses. + // + VarArg = VarArg->Next; + Tmp = VarArg; + Index = 0; + while (Tmp != NULL) { + Index ++; + Tmp = Tmp->Next; + } + + Dns = AllocatePool (Index * sizeof (EFI_IPv4_ADDRESS)); + if (Dns == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellNetwork1HiiHandle, L"ifconfig"); + ShellStatus = SHELL_OUT_OF_RESOURCES; + goto ON_EXIT; + } + Tmp = VarArg; + Index = 0; + while (Tmp != NULL) { + Status = NetLibStrToIp4 (Tmp->Arg, Dns + Index); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_INVALID_IPADDRESS), gShellNetwork1HiiHandle, Tmp->Arg); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + Index ++; + Tmp = Tmp->Next; + } + + VarArg = Tmp; + + // + // Set DNS addresses. + // + DataSize = Index * sizeof (EFI_IPv4_ADDRESS); + + Status = IfCb->IfCfg->SetData ( + IfCb->IfCfg, + Ip4Config2DataTypeDnsServer, + DataSize, + Dns + ); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellNetwork1HiiHandle, L"ifconfig"); + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + } + } + +ON_EXIT: + if (Dns != NULL) { + FreePool (Dns); + } + + return ShellStatus; + +} + +/** + The ifconfig command main process. + + @param[in] Private The pointer of IFCONFIG_PRIVATE_DATA. + + @retval SHELL_SUCCESS ifconfig command processed successfully. + @retval others The ifconfig command process failed. + +**/ +SHELL_STATUS +IfConfig ( + IN IFCONFIG_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + + ShellStatus = SHELL_SUCCESS; + + // + // Get configure information of all interfaces. + // + Status = IfConfigGetInterfaceInfo ( + Private->IfName, + &Private->IfList + ); + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_NOT_FOUND; + goto ON_EXIT; + } + + switch (Private->OpCode) { + case IfConfigOpList: + ShellStatus = IfConfigShowInterfaceInfo (&Private->IfList); + break; + + case IfConfigOpClear: + ShellStatus = IfConfigClearInterfaceInfo (&Private->IfList, Private->IfName); + break; + + case IfConfigOpSet: + ShellStatus = IfConfigSetInterfaceInfo (&Private->IfList, Private->VarArg); + break; + + default: + ShellStatus = SHELL_UNSUPPORTED; + } + +ON_EXIT: + return ShellStatus; +} + +/** + The ifconfig command cleanup process, free the allocated memory. + + @param[in] Private The pointer of IFCONFIG_PRIVATE_DATA. + +**/ +VOID +IfConfigCleanup ( + IN IFCONFIG_PRIVATE_DATA *Private + ) +{ + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + IFCONFIG_INTERFACE_CB *IfCb; + + ASSERT (Private != NULL); + + // + // Clean the list which save the set config Args. + // + if (Private->VarArg != NULL) { + FreeArgList (Private->VarArg); + } + + if (Private->IfName != NULL) { + FreePool (Private->IfName); + } + + // + // Clean the IFCONFIG_INTERFACE_CB list. + // + NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->IfList) { + IfCb = NET_LIST_USER_STRUCT (Entry, IFCONFIG_INTERFACE_CB, Link); + + RemoveEntryList (&IfCb->Link); + + if (IfCb->IfInfo != NULL) { + + FreePool (IfCb->IfInfo); + } + + FreePool (IfCb); + } + + FreePool (Private); +} + +/** + Function for 'ifconfig' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). + + @retval EFI_SUCCESS ifconfig command processed successfully. + @retval others The ifconfig command process failed. + +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunIfconfig ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + IFCONFIG_PRIVATE_DATA *Private; + LIST_ENTRY *ParamPackage; + SHELL_STATUS ShellStatus; + CONST CHAR16 *ValueStr; + ARG_LIST *ArgList; + CHAR16 *ProblemParam; + CHAR16 *Str; + + Status = EFI_INVALID_PARAMETER; + Private = NULL; + ShellStatus = SHELL_SUCCESS; + + Status = ShellCommandLineParseEx (mIfConfigCheckList, &ParamPackage, &ProblemParam, TRUE, FALSE); + if (EFI_ERROR (Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ifconfig", ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + + goto ON_EXIT; + } + + // + // To handle unsupported option. + // + if (ShellCommandLineGetFlag (ParamPackage, L"-c")) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_UNSUPPORTED_OPTION), gShellNetwork1HiiHandle,L"-c"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + + // + // To handle no option. + // + if (!ShellCommandLineGetFlag (ParamPackage, L"-r") && !ShellCommandLineGetFlag (ParamPackage, L"-s") && + !ShellCommandLineGetFlag (ParamPackage, L"-l")) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_LACK_OPTION), gShellNetwork1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + + // + // To handle conflict options. + // + if (((ShellCommandLineGetFlag (ParamPackage, L"-r")) && (ShellCommandLineGetFlag (ParamPackage, L"-s"))) || + ((ShellCommandLineGetFlag (ParamPackage, L"-r")) && (ShellCommandLineGetFlag (ParamPackage, L"-l"))) || + ((ShellCommandLineGetFlag (ParamPackage, L"-s")) && (ShellCommandLineGetFlag (ParamPackage, L"-l")))) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CON), gShellNetwork1HiiHandle, L"ifconfig"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + + Private = AllocateZeroPool (sizeof (IFCONFIG_PRIVATE_DATA)); + if (Private == NULL) { + ShellStatus = SHELL_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + InitializeListHead (&Private->IfList); + + // + // To get interface name for the list option. + // + if (ShellCommandLineGetFlag (ParamPackage, L"-l")) { + Private->OpCode = IfConfigOpList; + ValueStr = ShellCommandLineGetValue (ParamPackage, L"-l"); + if (ValueStr != NULL) { + Str = AllocateCopyPool (StrSize (ValueStr), ValueStr); + if (Str == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellNetwork1HiiHandle, L"ifconfig"); + ShellStatus = SHELL_OUT_OF_RESOURCES; + goto ON_EXIT; + } + Private->IfName = Str; + } + } + + // + // To get interface name for the clear option. + // + if (ShellCommandLineGetFlag (ParamPackage, L"-r")) { + Private->OpCode = IfConfigOpClear; + ValueStr = ShellCommandLineGetValue (ParamPackage, L"-r"); + if (ValueStr != NULL) { + Str = AllocateCopyPool (StrSize (ValueStr), ValueStr); + if (Str == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellNetwork1HiiHandle, L"ifconfig"); + ShellStatus = SHELL_OUT_OF_RESOURCES; + goto ON_EXIT; + } + Private->IfName = Str; + } + } + + // + // To get interface name and corresponding Args for the set option. + // + if (ShellCommandLineGetFlag (ParamPackage, L"-s")) { + ValueStr = ShellCommandLineGetValue (ParamPackage, L"-s"); + if (ValueStr == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_LACK_INTERFACE), gShellNetwork1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + + // + // To split the configuration into multi-section. + // + ArgList = SplitStrToList (ValueStr, L' '); + if (ArgList == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellNetwork1HiiHandle, L"ifconfig"); + ShellStatus = SHELL_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + Private->OpCode = IfConfigOpSet; + Private->IfName = ArgList->Arg; + + Private->VarArg = ArgList->Next; + + if (Private->IfName == NULL || Private->VarArg == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_LACK_COMMAND), gShellNetwork1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + } + + // + // Main process of ifconfig. + // + ShellStatus = IfConfig (Private); + +ON_EXIT: + + ShellCommandLineFreeVarList (ParamPackage); + + if (Private != NULL) { + IfConfigCleanup (Private); + } + + return ShellStatus; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ping.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ping.c new file mode 100644 index 00000000..33106eae --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ping.c @@ -0,0 +1,1708 @@ +/** @file + The implementation for Ping shell command. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellNetwork1CommandsLib.h" + +#define PING_IP4_COPY_ADDRESS(Dest, Src) (CopyMem ((Dest), (Src), sizeof (EFI_IPv4_ADDRESS))) + +UINT64 mCurrentTick = 0; + +// +// Function templates to match the IPv4 and IPv6 commands that we use. +// +typedef +EFI_STATUS +(EFIAPI *PING_IPX_POLL)( + IN VOID *This + ); + +typedef +EFI_STATUS +(EFIAPI *PING_IPX_TRANSMIT)( + IN VOID *This, + IN VOID *Token + ); + +typedef +EFI_STATUS +(EFIAPI *PING_IPX_RECEIVE)( + IN VOID *This, + IN VOID *Token + ); + +typedef +EFI_STATUS +(EFIAPI *PING_IPX_CANCEL)( + IN VOID *This, + IN VOID *Token OPTIONAL + ); + +/// +/// A set of pointers to either IPv6 or IPv4 functions. +/// Unknown which one to the ping command. +/// +typedef struct { + PING_IPX_TRANSMIT Transmit; + PING_IPX_RECEIVE Receive; + PING_IPX_CANCEL Cancel; + PING_IPX_POLL Poll; +}PING_IPX_PROTOCOL; + + +typedef union { + VOID *RxData; + VOID *TxData; +} PING_PACKET; + +// +// PING_IPX_COMPLETION_TOKEN +// structures are used for both transmit and receive operations. +// This version is IP-unaware. +// +typedef struct { + EFI_EVENT Event; + EFI_STATUS Status; + PING_PACKET Packet; +} PING_IPX_COMPLETION_TOKEN; + +#pragma pack(1) +typedef struct _ICMPX_ECHO_REQUEST_REPLY { + UINT8 Type; + UINT8 Code; + UINT16 Checksum; + UINT16 Identifier; + UINT16 SequenceNum; + UINT32 TimeStamp; + UINT8 Data[1]; +} ICMPX_ECHO_REQUEST_REPLY; +#pragma pack() + +typedef struct _PING_ICMP_TX_INFO { + LIST_ENTRY Link; + UINT16 SequenceNum; + UINT32 TimeStamp; + PING_IPX_COMPLETION_TOKEN *Token; +} PING_ICMPX_TX_INFO; + +#define DEFAULT_TIMEOUT 5000 +#define MAX_SEND_NUMBER 10000 +#define MAX_BUFFER_SIZE 32768 +#define DEFAULT_TIMER_PERIOD 358049 +#define ONE_SECOND 10000000 +#define PING_IP_CHOICE_IP4 1 +#define PING_IP_CHOICE_IP6 2 +#define DEFAULT_SEND_COUNT 10 +#define DEFAULT_BUFFER_SIZE 16 +#define ICMP_V4_ECHO_REQUEST 0x8 +#define ICMP_V4_ECHO_REPLY 0x0 +#define STALL_1_MILLI_SECOND 1000 + +#define PING_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('P', 'i', 'n', 'g') +typedef struct _PING_PRIVATE_DATA { + UINT32 Signature; + EFI_HANDLE NicHandle; + EFI_HANDLE IpChildHandle; + EFI_EVENT Timer; + + UINT32 TimerPeriod; + UINT32 RttTimerTick; + EFI_EVENT RttTimer; + + EFI_STATUS Status; + LIST_ENTRY TxList; + UINT16 RxCount; + UINT16 TxCount; + UINT64 RttSum; + UINT64 RttMin; + UINT64 RttMax; + UINT32 SequenceNum; + + UINT32 SendNum; + UINT32 BufferSize; + UINT32 IpChoice; + + PING_IPX_PROTOCOL ProtocolPointers; + VOID *IpProtocol; + UINT8 SrcAddress[MAX(sizeof(EFI_IPv6_ADDRESS) , sizeof(EFI_IPv4_ADDRESS) )]; + UINT8 DstAddress[MAX(sizeof(EFI_IPv6_ADDRESS) , sizeof(EFI_IPv4_ADDRESS) )]; + PING_IPX_COMPLETION_TOKEN RxToken; + UINT16 FailedCount; +} PING_PRIVATE_DATA; + +/** + Calculate the internet checksum (see RFC 1071). + + @param[in] Packet Buffer which contains the data to be checksummed. + @param[in] Length Length to be checksummed. + + @retval Checksum Returns the 16 bit ones complement of + ones complement sum of 16 bit words +**/ +UINT16 +NetChecksum ( + IN UINT8 *Buffer, + IN UINT32 Length + ) +{ + UINT32 Sum; + UINT8 Odd; + UINT16 *Packet; + + Packet = (UINT16 *) Buffer; + + Sum = 0; + Odd = (UINT8) (Length & 1); + Length >>= 1; + while ((Length--) != 0) { + Sum += *Packet++; + } + + if (Odd != 0) { + Sum += *(UINT8 *) Packet; + } + + Sum = (Sum & 0xffff) + (Sum >> 16); + + // + // in case above carried + // + Sum += Sum >> 16; + + return (UINT16) Sum; +} + +/** + Reads and returns the current value of register. + In IA64, the register is the Interval Timer Vector (ITV). + In X86(IA32/X64), the register is the Time Stamp Counter (TSC) + + @return The current value of the register. + +**/ + +STATIC CONST SHELL_PARAM_ITEM PingParamList[] = { + { + L"-l", + TypeValue + }, + { + L"-n", + TypeValue + }, + { + L"-s", + TypeValue + }, + { + L"-_s", + TypeValue + }, + { + L"-_ip6", + TypeFlag + }, + { + NULL, + TypeMax + }, +}; + +// +// Global Variables in Ping command. +// +STATIC CONST CHAR16 *mDstString; +STATIC CONST CHAR16 *mSrcString; + +/** + RTT timer tick routine. + + @param[in] Event A EFI_EVENT type event. + @param[in] Context The pointer to Context. + +**/ +VOID +EFIAPI +RttTimerTickRoutine ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UINT32 *RttTimerTick; + + RttTimerTick = (UINT32*) Context; + (*RttTimerTick)++; +} + +/** + Get the timer period of the system. + + This function tries to get the system timer period by creating + an 1ms period timer. + + @return System timer period in MS, or 0 if operation failed. + +**/ +UINT32 +GetTimerPeriod( + VOID + ) +{ + EFI_STATUS Status; + UINT32 RttTimerTick; + EFI_EVENT TimerEvent; + UINT32 StallCounter; + EFI_TPL OldTpl; + + RttTimerTick = 0; + StallCounter = 0; + + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + RttTimerTickRoutine, + &RttTimerTick, + &TimerEvent + ); + if (EFI_ERROR (Status)) { + return 0; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + Status = gBS->SetTimer ( + TimerEvent, + TimerPeriodic, + TICKS_PER_MS + ); + if (EFI_ERROR (Status)) { + gBS->CloseEvent (TimerEvent); + return 0; + } + + while (RttTimerTick < 10) { + gBS->Stall (STALL_1_MILLI_SECOND); + ++StallCounter; + } + + gBS->RestoreTPL (OldTpl); + + gBS->SetTimer (TimerEvent, TimerCancel, 0); + gBS->CloseEvent (TimerEvent); + + return StallCounter / RttTimerTick; +} + +/** + Initialize the timer event for RTT (round trip time). + + @param[in] Private The pointer to PING_PRIVATE_DATA. + + @retval EFI_SUCCESS RTT timer is started. + @retval Others Failed to start the RTT timer. + +**/ +EFI_STATUS +PingInitRttTimer ( + PING_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + + Private->TimerPeriod = GetTimerPeriod (); + if (Private->TimerPeriod == 0) { + return EFI_ABORTED; + } + + Private->RttTimerTick = 0; + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + RttTimerTickRoutine, + &Private->RttTimerTick, + &Private->RttTimer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->SetTimer ( + Private->RttTimer, + TimerPeriodic, + TICKS_PER_MS + ); + if (EFI_ERROR (Status)) { + gBS->CloseEvent (Private->RttTimer); + return Status; + } + + return EFI_SUCCESS; +} + +/** + Free RTT timer event resource. + + @param[in] Private The pointer to PING_PRIVATE_DATA. + +**/ +VOID +PingFreeRttTimer ( + PING_PRIVATE_DATA *Private + ) +{ + if (Private->RttTimer != NULL) { + gBS->SetTimer (Private->RttTimer, TimerCancel, 0); + gBS->CloseEvent (Private->RttTimer); + } +} + +/** + Read the current time. + + @param[in] Private The pointer to PING_PRIVATE_DATA. + + @retval the current tick value. +**/ +UINT32 +ReadTime ( + PING_PRIVATE_DATA *Private + ) +{ + return Private->RttTimerTick; +} + +/** + Calculate a duration in ms. + + @param[in] Private The pointer to PING_PRIVATE_DATA. + @param[in] Begin The start point of time. + @param[in] End The end point of time. + + @return The duration in ms. + @retval 0 The parameters were not valid. +**/ +UINT32 +CalculateTick ( + PING_PRIVATE_DATA *Private, + IN UINT32 Begin, + IN UINT32 End + ) +{ + if (End < Begin) { + return (0); + } + + return (End - Begin) * Private->TimerPeriod; +} + +/** + Destroy PING_ICMPX_TX_INFO, and recollect the memory. + + @param[in] TxInfo The pointer to PING_ICMPX_TX_INFO. + @param[in] IpChoice Whether the token is IPv4 or IPv6 +**/ +VOID +PingDestroyTxInfo ( + IN PING_ICMPX_TX_INFO *TxInfo, + IN UINT32 IpChoice + ) +{ + EFI_IP6_TRANSMIT_DATA *Ip6TxData; + EFI_IP4_TRANSMIT_DATA *Ip4TxData; + EFI_IP6_FRAGMENT_DATA *FragData; + UINTN Index; + + if (TxInfo == NULL) { + return; + } + + if (TxInfo->Token != NULL) { + + if (TxInfo->Token->Event != NULL) { + gBS->CloseEvent (TxInfo->Token->Event); + } + + if (TxInfo->Token->Packet.TxData != NULL) { + if (IpChoice == PING_IP_CHOICE_IP6) { + Ip6TxData = TxInfo->Token->Packet.TxData; + + if (Ip6TxData->OverrideData != NULL) { + FreePool (Ip6TxData->OverrideData); + } + + if (Ip6TxData->ExtHdrs != NULL) { + FreePool (Ip6TxData->ExtHdrs); + } + + for (Index = 0; Index < Ip6TxData->FragmentCount; Index++) { + FragData = Ip6TxData->FragmentTable[Index].FragmentBuffer; + if (FragData != NULL) { + FreePool (FragData); + } + } + } else { + Ip4TxData = TxInfo->Token->Packet.TxData; + + if (Ip4TxData->OverrideData != NULL) { + FreePool (Ip4TxData->OverrideData); + } + + for (Index = 0; Index < Ip4TxData->FragmentCount; Index++) { + FragData = Ip4TxData->FragmentTable[Index].FragmentBuffer; + if (FragData != NULL) { + FreePool (FragData); + } + } + } + } + + FreePool (TxInfo->Token); + } + + FreePool (TxInfo); +} + +/** + Match the request, and reply with SequenceNum/TimeStamp. + + @param[in] Private The pointer to PING_PRIVATE_DATA. + @param[in] Packet The pointer to ICMPX_ECHO_REQUEST_REPLY. + + @retval EFI_SUCCESS The match is successful. + @retval EFI_NOT_FOUND The reply can't be matched with any request. + +**/ +EFI_STATUS +Ping6MatchEchoReply ( + IN PING_PRIVATE_DATA *Private, + IN ICMPX_ECHO_REQUEST_REPLY *Packet + ) +{ + PING_ICMPX_TX_INFO *TxInfo; + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + + NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) { + TxInfo = BASE_CR (Entry, PING_ICMPX_TX_INFO, Link); + + if ((TxInfo->SequenceNum == Packet->SequenceNum) && (TxInfo->TimeStamp == Packet->TimeStamp)) { + Private->RxCount++; + RemoveEntryList (&TxInfo->Link); + PingDestroyTxInfo (TxInfo, Private->IpChoice); + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** + The original intention is to send a request. + Currently, the application retransmits an icmp6 echo request packet + per second in sendnumber times that is specified by the user. + Because nothing can be done here, all things move to the timer rountine. + + @param[in] Event A EFI_EVENT type event. + @param[in] Context The pointer to Context. + +**/ +VOID +EFIAPI +Ping6OnEchoRequestSent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ +} + +/** + receive reply, match and print reply infomation. + + @param[in] Event A EFI_EVENT type event. + @param[in] Context The pointer to context. + +**/ +VOID +EFIAPI +Ping6OnEchoReplyReceived ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + PING_PRIVATE_DATA *Private; + ICMPX_ECHO_REQUEST_REPLY *Reply; + UINT32 PayLoad; + UINT32 Rtt; + + Private = (PING_PRIVATE_DATA *) Context; + + if (Private == NULL || Private->Status == EFI_ABORTED || Private->Signature != PING_PRIVATE_DATA_SIGNATURE) { + return; + } + + if (Private->RxToken.Packet.RxData == NULL) { + return; + } + + if (Private->IpChoice == PING_IP_CHOICE_IP6) { + Reply = ((EFI_IP6_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->FragmentTable[0].FragmentBuffer; + PayLoad = ((EFI_IP6_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->DataLength; + if (((EFI_IP6_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->Header->NextHeader != IP6_ICMP) { + goto ON_EXIT; + } + if (!IP6_IS_MULTICAST ((EFI_IPv6_ADDRESS*)&Private->DstAddress) && + !EFI_IP6_EQUAL (&((EFI_IP6_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->Header->SourceAddress, (EFI_IPv6_ADDRESS*)&Private->DstAddress)) { + goto ON_EXIT; + } + + if ((Reply->Type != ICMP_V6_ECHO_REPLY) || (Reply->Code != 0)) { + goto ON_EXIT; + } + } else { + Reply = ((EFI_IP4_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->FragmentTable[0].FragmentBuffer; + PayLoad = ((EFI_IP4_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->DataLength; + if (!IP4_IS_MULTICAST (EFI_IP4(*(EFI_IPv4_ADDRESS*)Private->DstAddress)) && + !EFI_IP4_EQUAL (&((EFI_IP4_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->Header->SourceAddress, (EFI_IPv4_ADDRESS*)&Private->DstAddress)) { + goto ON_EXIT; + } + + if ((Reply->Type != ICMP_V4_ECHO_REPLY) || (Reply->Code != 0)) { + goto ON_EXIT; + } + } + + + if (PayLoad != Private->BufferSize) { + goto ON_EXIT; + } + // + // Check whether the reply matches the sent request before. + // + Status = Ping6MatchEchoReply (Private, Reply); + if (EFI_ERROR(Status)) { + goto ON_EXIT; + } + // + // Display statistics on this icmp6 echo reply packet. + // + Rtt = CalculateTick (Private, Reply->TimeStamp, ReadTime (Private)); + + Private->RttSum += Rtt; + Private->RttMin = Private->RttMin > Rtt ? Rtt : Private->RttMin; + Private->RttMax = Private->RttMax < Rtt ? Rtt : Private->RttMax; + + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_PING_REPLY_INFO), + gShellNetwork1HiiHandle, + PayLoad, + mDstString, + Reply->SequenceNum, + Private->IpChoice == PING_IP_CHOICE_IP6?((EFI_IP6_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->Header->HopLimit:0, + Rtt, + Rtt + Private->TimerPeriod + ); + +ON_EXIT: + + // + // Recycle the packet before reusing RxToken + // + gBS->SignalEvent (Private->IpChoice == PING_IP_CHOICE_IP6?((EFI_IP6_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->RecycleSignal:((EFI_IP4_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->RecycleSignal); + + if (Private->RxCount < Private->SendNum) { + // + // Continue to receive icmp echo reply packets. + // + Private->RxToken.Status = EFI_ABORTED; + + Status = Private->ProtocolPointers.Receive (Private->IpProtocol, &Private->RxToken); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_RECEIVE), gShellNetwork1HiiHandle, Status); + Private->Status = EFI_ABORTED; + } + } else { + // + // All reply have already been received from the dest host. + // + Private->Status = EFI_SUCCESS; + } +} + +/** + Create a PING_IPX_COMPLETION_TOKEN. + + @param[in] Private The pointer of PING_PRIVATE_DATA. + @param[in] TimeStamp The TimeStamp of request. + @param[in] SequenceNum The SequenceNum of request. + + @return The pointer of PING_IPX_COMPLETION_TOKEN. + +**/ +PING_IPX_COMPLETION_TOKEN * +PingGenerateToken ( + IN PING_PRIVATE_DATA *Private, + IN UINT32 TimeStamp, + IN UINT16 SequenceNum + ) +{ + EFI_STATUS Status; + PING_IPX_COMPLETION_TOKEN *Token; + VOID *TxData; + ICMPX_ECHO_REQUEST_REPLY *Request; + UINT16 HeadSum; + UINT16 TempChecksum; + + Request = AllocateZeroPool (Private->BufferSize); + if (Request == NULL) { + return NULL; + } + TxData = AllocateZeroPool (Private->IpChoice==PING_IP_CHOICE_IP6?sizeof (EFI_IP6_TRANSMIT_DATA):sizeof (EFI_IP4_TRANSMIT_DATA)); + if (TxData == NULL) { + FreePool (Request); + return NULL; + } + Token = AllocateZeroPool (sizeof (PING_IPX_COMPLETION_TOKEN)); + if (Token == NULL) { + FreePool (Request); + FreePool (TxData); + return NULL; + } + + // + // Assembly echo request packet. + // + Request->Type = (UINT8)(Private->IpChoice==PING_IP_CHOICE_IP6?ICMP_V6_ECHO_REQUEST:ICMP_V4_ECHO_REQUEST); + Request->Code = 0; + Request->SequenceNum = SequenceNum; + Request->Identifier = 0; + Request->Checksum = 0; + + // + // Assembly token for transmit. + // + if (Private->IpChoice==PING_IP_CHOICE_IP6) { + Request->TimeStamp = TimeStamp; + ((EFI_IP6_TRANSMIT_DATA*)TxData)->ExtHdrsLength = 0; + ((EFI_IP6_TRANSMIT_DATA*)TxData)->ExtHdrs = NULL; + ((EFI_IP6_TRANSMIT_DATA*)TxData)->OverrideData = 0; + ((EFI_IP6_TRANSMIT_DATA*)TxData)->DataLength = Private->BufferSize; + ((EFI_IP6_TRANSMIT_DATA*)TxData)->FragmentCount = 1; + ((EFI_IP6_TRANSMIT_DATA*)TxData)->FragmentTable[0].FragmentBuffer = (VOID *) Request; + ((EFI_IP6_TRANSMIT_DATA*)TxData)->FragmentTable[0].FragmentLength = Private->BufferSize; + } else { + ((EFI_IP4_TRANSMIT_DATA*)TxData)->OptionsLength = 0; + ((EFI_IP4_TRANSMIT_DATA*)TxData)->OptionsBuffer = NULL; + ((EFI_IP4_TRANSMIT_DATA*)TxData)->OverrideData = 0; + ((EFI_IP4_TRANSMIT_DATA*)TxData)->TotalDataLength = Private->BufferSize; + ((EFI_IP4_TRANSMIT_DATA*)TxData)->FragmentCount = 1; + ((EFI_IP4_TRANSMIT_DATA*)TxData)->FragmentTable[0].FragmentBuffer = (VOID *) Request; + ((EFI_IP4_TRANSMIT_DATA*)TxData)->FragmentTable[0].FragmentLength = Private->BufferSize; + ((EFI_IP4_TRANSMIT_DATA*)TxData)->DestinationAddress.Addr[0] = Private->DstAddress[0]; + ((EFI_IP4_TRANSMIT_DATA*)TxData)->DestinationAddress.Addr[1] = Private->DstAddress[1]; + ((EFI_IP4_TRANSMIT_DATA*)TxData)->DestinationAddress.Addr[2] = Private->DstAddress[2]; + ((EFI_IP4_TRANSMIT_DATA*)TxData)->DestinationAddress.Addr[3] = Private->DstAddress[3]; + + HeadSum = NetChecksum ((UINT8 *) Request, Private->BufferSize); + Request->TimeStamp = TimeStamp; + TempChecksum = NetChecksum ((UINT8 *) &Request->TimeStamp, sizeof (UINT64)); + Request->Checksum = (UINT16)(~NetAddChecksum (HeadSum, TempChecksum)); + } + + + Token->Status = EFI_ABORTED; + Token->Packet.TxData = TxData; + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + Ping6OnEchoRequestSent, + Private, + &Token->Event + ); + + if (EFI_ERROR (Status)) { + FreePool (Request); + FreePool (TxData); + FreePool (Token); + return NULL; + } + + return Token; +} + +/** + Transmit the PING_IPX_COMPLETION_TOKEN. + + @param[in] Private The pointer of PING_PRIVATE_DATA. + + @retval EFI_SUCCESS Transmitted successfully. + @retval EFI_OUT_OF_RESOURCES No memory is available on the platform. + @retval others Transmitted unsuccessfully. + +**/ +EFI_STATUS +PingSendEchoRequest ( + IN PING_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + PING_ICMPX_TX_INFO *TxInfo; + + TxInfo = AllocateZeroPool (sizeof (PING_ICMPX_TX_INFO)); + + if (TxInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + TxInfo->TimeStamp = ReadTime (Private); + TxInfo->SequenceNum = (UINT16) (Private->TxCount + 1); + TxInfo->Token = PingGenerateToken ( + Private, + TxInfo->TimeStamp, + TxInfo->SequenceNum + ); + + if (TxInfo->Token == NULL) { + PingDestroyTxInfo (TxInfo, Private->IpChoice); + return EFI_OUT_OF_RESOURCES; + } + + ASSERT(Private->ProtocolPointers.Transmit != NULL); + + InsertTailList (&Private->TxList, &TxInfo->Link); + + Status = Private->ProtocolPointers.Transmit (Private->IpProtocol, TxInfo->Token); + + if (EFI_ERROR (Status)) { + RemoveEntryList (&TxInfo->Link); + PingDestroyTxInfo (TxInfo, Private->IpChoice); + return Status; + } + + Private->TxCount++; + + return EFI_SUCCESS; +} + +/** + Place a completion token into the receive packet queue to receive the echo reply. + + @param[in] Private The pointer of PING_PRIVATE_DATA. + + @retval EFI_SUCCESS Put the token into the receive packet queue successfully. + @retval others Put the token into the receive packet queue unsuccessfully. + +**/ +EFI_STATUS +Ping6ReceiveEchoReply ( + IN PING_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + + ZeroMem (&Private->RxToken, sizeof (PING_IPX_COMPLETION_TOKEN)); + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + Ping6OnEchoReplyReceived, + Private, + &Private->RxToken.Event + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Private->RxToken.Status = EFI_NOT_READY; + + Status = Private->ProtocolPointers.Receive (Private->IpProtocol, &Private->RxToken); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_RECEIVE), gShellNetwork1HiiHandle, Status); + } + return Status; +} + +/** + Remove the timeout request from the list. + + @param[in] Event A EFI_EVENT type event. + @param[in] Context The pointer to Context. + +**/ +VOID +EFIAPI +Ping6OnTimerRoutine ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + PING_PRIVATE_DATA *Private; + PING_ICMPX_TX_INFO *TxInfo; + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + UINT64 Time; + + Private = (PING_PRIVATE_DATA *) Context; + if (Private->Signature != PING_PRIVATE_DATA_SIGNATURE) { + Private->Status = EFI_NOT_FOUND; + return; + } + + // + // Retransmit icmp6 echo request packets per second in sendnumber times. + // + if (Private->TxCount < Private->SendNum) { + + Status = PingSendEchoRequest (Private); + if (Private->TxCount != 0){ + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_SEND_REQUEST), gShellNetwork1HiiHandle, Private->TxCount + 1); + } + } + } + // + // Check whether any icmp6 echo request in the list timeout. + // + NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) { + TxInfo = BASE_CR (Entry, PING_ICMPX_TX_INFO, Link); + Time = CalculateTick (Private, TxInfo->TimeStamp, ReadTime (Private)); + + // + // Remove the timeout echo request from txlist. + // + if (Time > DEFAULT_TIMEOUT) { + + if (EFI_ERROR (TxInfo->Token->Status)) { + Private->ProtocolPointers.Cancel (Private->IpProtocol, TxInfo->Token); + } + // + // Remove the timeout icmp6 echo request from list. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_TIMEOUT), gShellNetwork1HiiHandle, TxInfo->SequenceNum); + + RemoveEntryList (&TxInfo->Link); + PingDestroyTxInfo (TxInfo, Private->IpChoice); + + Private->RxCount++; + Private->FailedCount++; + + if (IsListEmpty (&Private->TxList) && (Private->TxCount == Private->SendNum)) { + // + // All the left icmp6 echo request in the list timeout. + // + Private->Status = EFI_TIMEOUT; + } + } + } +} + +/** + Determine if a IP4 address is Link Local. + + 169.254.1.0 through 169.254.254.255 is link local. + + @param[in] Address The address to test. + + @retval TRUE It is. + @retval FALSE It is not. +**/ +BOOLEAN +PingNetIp4IsLinkLocalAddr ( + IN CONST EFI_IPv4_ADDRESS *Address + ) +{ + return ((BOOLEAN)(Address->Addr[0] == 169 && Address->Addr[1] == 254 && Address->Addr[2] >= 1 && Address->Addr[2] <= 254)); +} + +/** + Determine if a IP4 address is unspecified. + + @param[in] Address The address to test. + + @retval TRUE It is. + @retval FALSE It is not. +**/ +BOOLEAN +PingNetIp4IsUnspecifiedAddr ( + IN CONST EFI_IPv4_ADDRESS *Address + ) +{ + return ((BOOLEAN)((ReadUnaligned32 ((UINT32*)&Address->Addr[0])) == 0x00000000)); +} + +/** + Create a valid IP instance. + + @param[in] Private The pointer of PING_PRIVATE_DATA. + + @retval EFI_SUCCESS Create a valid IPx instance successfully. + @retval EFI_ABORTED Locate handle with ipx service binding protocol unsuccessfully. + @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link-local address. + @retval EFI_OUT_OF_RESOURCES No memory is available on the platform. + @retval EFI_NOT_FOUND The source address is not found. +**/ +EFI_STATUS +PingCreateIpInstance ( + IN PING_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + UINTN HandleIndex; + UINTN HandleNum; + EFI_HANDLE *HandleBuffer; + BOOLEAN UnspecifiedSrc; + EFI_STATUS MediaStatus; + EFI_SERVICE_BINDING_PROTOCOL *EfiSb; + VOID *IpXCfg; + EFI_IP6_CONFIG_DATA Ip6Config; + EFI_IP4_CONFIG_DATA Ip4Config; + VOID *IpXInterfaceInfo; + UINTN IfInfoSize; + EFI_IPv6_ADDRESS *Addr; + UINTN AddrIndex; + + HandleBuffer = NULL; + UnspecifiedSrc = FALSE; + MediaStatus = EFI_SUCCESS; + EfiSb = NULL; + IpXInterfaceInfo = NULL; + IfInfoSize = 0; + + // + // Locate all the handles with ip6 service binding protocol. + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ServiceBindingProtocolGuid:&gEfiIp4ServiceBindingProtocolGuid, + NULL, + &HandleNum, + &HandleBuffer + ); + if (EFI_ERROR (Status) || (HandleNum == 0) || (HandleBuffer == NULL)) { + return EFI_ABORTED; + } + + if (Private->IpChoice == PING_IP_CHOICE_IP6 ? NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS*)&Private->SrcAddress) : \ + PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS*)&Private->SrcAddress)) { + // + // SrcAddress is unspecified. So, both connected and configured interface will be automatic selected. + // + UnspecifiedSrc = TRUE; + } + + // + // Source address is required when pinging a link-local address. + // + if (Private->IpChoice == PING_IP_CHOICE_IP6) { + if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS*)&Private->DstAddress) && UnspecifiedSrc) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_INVALID_SOURCE), gShellNetwork1HiiHandle); + Status = EFI_INVALID_PARAMETER; + goto ON_ERROR; + } + } else { + ASSERT(Private->IpChoice == PING_IP_CHOICE_IP4); + if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS*)&Private->DstAddress) && UnspecifiedSrc) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_INVALID_SOURCE), gShellNetwork1HiiHandle); + Status = EFI_INVALID_PARAMETER; + goto ON_ERROR; + } + } + + // + // For each ip6 protocol, check interface addresses list. + // + for (HandleIndex = 0; HandleIndex < HandleNum; HandleIndex++) { + EfiSb = NULL; + IpXInterfaceInfo = NULL; + IfInfoSize = 0; + + if (UnspecifiedSrc) { + // + // Check media. + // + NetLibDetectMediaWaitTimeout (HandleBuffer[HandleIndex], 0, &MediaStatus); + if (MediaStatus != EFI_SUCCESS) { + // + // Skip this one. + // + continue; + } + } + + Status = gBS->HandleProtocol ( + HandleBuffer[HandleIndex], + Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ServiceBindingProtocolGuid:&gEfiIp4ServiceBindingProtocolGuid, + (VOID **) &EfiSb + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Ip6config protocol and ip6 service binding protocol are installed + // on the same handle. + // + Status = gBS->HandleProtocol ( + HandleBuffer[HandleIndex], + Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ConfigProtocolGuid:&gEfiIp4Config2ProtocolGuid, + (VOID **) &IpXCfg + ); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + // + // Get the interface information size. + // + if (Private->IpChoice == PING_IP_CHOICE_IP6) { + Status = ((EFI_IP6_CONFIG_PROTOCOL*)IpXCfg)->GetData ( + IpXCfg, + Ip6ConfigDataTypeInterfaceInfo, + &IfInfoSize, + NULL + ); + } else { + Status = ((EFI_IP4_CONFIG2_PROTOCOL*)IpXCfg)->GetData ( + IpXCfg, + Ip4Config2DataTypeInterfaceInfo, + &IfInfoSize, + NULL + ); + } + + // + // Skip the ones not in current use. + // + if (Status == EFI_NOT_STARTED) { + continue; + } + + if (Status != EFI_BUFFER_TOO_SMALL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_GETDATA), gShellNetwork1HiiHandle, Status); + goto ON_ERROR; + } + + IpXInterfaceInfo = AllocateZeroPool (IfInfoSize); + + if (IpXInterfaceInfo == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + // + // Get the interface info. + // + if (Private->IpChoice == PING_IP_CHOICE_IP6) { + Status = ((EFI_IP6_CONFIG_PROTOCOL*)IpXCfg)->GetData ( + IpXCfg, + Ip6ConfigDataTypeInterfaceInfo, + &IfInfoSize, + IpXInterfaceInfo + ); + } else { + Status = ((EFI_IP4_CONFIG2_PROTOCOL*)IpXCfg)->GetData ( + IpXCfg, + Ip4Config2DataTypeInterfaceInfo, + &IfInfoSize, + IpXInterfaceInfo + ); + } + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_GETDATA), gShellNetwork1HiiHandle, Status); + goto ON_ERROR; + } + // + // Check whether the source address is one of the interface addresses. + // + if (Private->IpChoice == PING_IP_CHOICE_IP6) { + for (AddrIndex = 0; AddrIndex < ((EFI_IP6_CONFIG_INTERFACE_INFO*)IpXInterfaceInfo)->AddressInfoCount; AddrIndex++) { + Addr = &(((EFI_IP6_CONFIG_INTERFACE_INFO*)IpXInterfaceInfo)->AddressInfo[AddrIndex].Address); + + if (UnspecifiedSrc) { + if (!NetIp6IsUnspecifiedAddr (Addr) && !NetIp6IsLinkLocalAddr (Addr)) { + // + // Select the interface automatically. + // + CopyMem(&Private->SrcAddress, Addr, sizeof(Private->SrcAddress)); + break; + } + } else if (EFI_IP6_EQUAL (&Private->SrcAddress, Addr)) { + // + // Match a certain interface address. + // + break; + } + } + + if (AddrIndex < ((EFI_IP6_CONFIG_INTERFACE_INFO*)IpXInterfaceInfo)->AddressInfoCount) { + // + // Found a nic handle with right interface address. + // + break; + } + } else { + if (UnspecifiedSrc) { + if (!PingNetIp4IsUnspecifiedAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO*)IpXInterfaceInfo)->StationAddress) && + !PingNetIp4IsLinkLocalAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO*)IpXInterfaceInfo)->StationAddress)) { + // + // Select the interface automatically. + // + break; + } + } else if (EFI_IP4_EQUAL (&Private->SrcAddress, &((EFI_IP4_CONFIG2_INTERFACE_INFO*)IpXInterfaceInfo)->StationAddress)) { + // + // Match a certain interface address. + // + break; + } + } + + FreePool (IpXInterfaceInfo); + IpXInterfaceInfo = NULL; + } + // + // No exact interface address matched. + // + + if (HandleIndex == HandleNum) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_CONFIGD_NIC_NF), gShellNetwork1HiiHandle, L"ping"); + Status = EFI_NOT_FOUND; + goto ON_ERROR; + } + + Private->NicHandle = HandleBuffer[HandleIndex]; + + ASSERT (EfiSb != NULL); + Status = EfiSb->CreateChild (EfiSb, &Private->IpChildHandle); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + if (Private->IpChoice == PING_IP_CHOICE_IP6) { + Status = gBS->OpenProtocol ( + Private->IpChildHandle, + &gEfiIp6ProtocolGuid, + &Private->IpProtocol, + gImageHandle, + Private->IpChildHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + + ZeroMem (&Ip6Config, sizeof (EFI_IP6_CONFIG_DATA)); + + // + // Configure the ip6 instance for icmp6 packet exchange. + // + Ip6Config.DefaultProtocol = 58; + Ip6Config.AcceptAnyProtocol = FALSE; + Ip6Config.AcceptIcmpErrors = TRUE; + Ip6Config.AcceptPromiscuous = FALSE; + Ip6Config.TrafficClass = 0; + Ip6Config.HopLimit = 128; + Ip6Config.FlowLabel = 0; + Ip6Config.ReceiveTimeout = 0; + Ip6Config.TransmitTimeout = 0; + + IP6_COPY_ADDRESS (&Ip6Config.StationAddress, &Private->SrcAddress); + IP6_COPY_ADDRESS (&Ip6Config.DestinationAddress, &Private->DstAddress); + + Status = ((EFI_IP6_PROTOCOL*)(Private->IpProtocol))->Configure (Private->IpProtocol, &Ip6Config); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_CONFIG), gShellNetwork1HiiHandle, Status); + goto ON_ERROR; + } + + Private->ProtocolPointers.Transmit = (PING_IPX_TRANSMIT )((EFI_IP6_PROTOCOL*)Private->IpProtocol)->Transmit; + Private->ProtocolPointers.Receive = (PING_IPX_RECEIVE )((EFI_IP6_PROTOCOL*)Private->IpProtocol)->Receive; + Private->ProtocolPointers.Cancel = (PING_IPX_CANCEL )((EFI_IP6_PROTOCOL*)Private->IpProtocol)->Cancel; + Private->ProtocolPointers.Poll = (PING_IPX_POLL )((EFI_IP6_PROTOCOL*)Private->IpProtocol)->Poll; + } else { + Status = gBS->OpenProtocol ( + Private->IpChildHandle, + &gEfiIp4ProtocolGuid, + &Private->IpProtocol, + gImageHandle, + Private->IpChildHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + + ZeroMem (&Ip4Config, sizeof (EFI_IP4_CONFIG_DATA)); + + // + // Configure the ip4 instance for icmp4 packet exchange. + // + Ip4Config.DefaultProtocol = 1; + Ip4Config.AcceptAnyProtocol = FALSE; + Ip4Config.AcceptBroadcast = FALSE; + Ip4Config.AcceptIcmpErrors = TRUE; + Ip4Config.AcceptPromiscuous = FALSE; + Ip4Config.DoNotFragment = FALSE; + Ip4Config.RawData = FALSE; + Ip4Config.ReceiveTimeout = 0; + Ip4Config.TransmitTimeout = 0; + Ip4Config.UseDefaultAddress = TRUE; + Ip4Config.TimeToLive = 128; + Ip4Config.TypeOfService = 0; + + Status = ((EFI_IP4_PROTOCOL*)(Private->IpProtocol))->Configure (Private->IpProtocol, &Ip4Config); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_CONFIG), gShellNetwork1HiiHandle, Status); + goto ON_ERROR; + } + + Private->ProtocolPointers.Transmit = (PING_IPX_TRANSMIT )((EFI_IP4_PROTOCOL*)Private->IpProtocol)->Transmit; + Private->ProtocolPointers.Receive = (PING_IPX_RECEIVE )((EFI_IP4_PROTOCOL*)Private->IpProtocol)->Receive; + Private->ProtocolPointers.Cancel = (PING_IPX_CANCEL )((EFI_IP4_PROTOCOL*)Private->IpProtocol)->Cancel; + Private->ProtocolPointers.Poll = (PING_IPX_POLL )((EFI_IP4_PROTOCOL*)Private->IpProtocol)->Poll; + } + + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + + return EFI_SUCCESS; + +ON_ERROR: + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + + if (IpXInterfaceInfo != NULL) { + FreePool (IpXInterfaceInfo); + } + + if ((EfiSb != NULL) && (Private->IpChildHandle != NULL)) { + EfiSb->DestroyChild (EfiSb, Private->IpChildHandle); + } + + return Status; +} + +/** + Destroy the IP instance. + + @param[in] Private The pointer of PING_PRIVATE_DATA. + +**/ +VOID +Ping6DestroyIp6Instance ( + IN PING_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + EFI_SERVICE_BINDING_PROTOCOL *IpSb; + + gBS->CloseProtocol ( + Private->IpChildHandle, + Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ProtocolGuid:&gEfiIp4ProtocolGuid, + gImageHandle, + Private->IpChildHandle + ); + + Status = gBS->HandleProtocol ( + Private->NicHandle, + Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ServiceBindingProtocolGuid:&gEfiIp4ServiceBindingProtocolGuid, + (VOID **) &IpSb + ); + + if (!EFI_ERROR(Status)) { + IpSb->DestroyChild (IpSb, Private->IpChildHandle); + } +} + + +/** + The Ping Process. + + @param[in] SendNumber The send request count. + @param[in] BufferSize The send buffer size. + @param[in] SrcAddress The source address. + @param[in] DstAddress The destination address. + @param[in] IpChoice The choice between IPv4 and IPv6. + + @retval SHELL_SUCCESS The ping processed successfullly. + @retval others The ping processed unsuccessfully. +**/ +SHELL_STATUS +ShellPing ( + IN UINT32 SendNumber, + IN UINT32 BufferSize, + IN EFI_IPv6_ADDRESS *SrcAddress, + IN EFI_IPv6_ADDRESS *DstAddress, + IN UINT32 IpChoice + ) +{ + EFI_STATUS Status; + PING_PRIVATE_DATA *Private; + PING_ICMPX_TX_INFO *TxInfo; + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + SHELL_STATUS ShellStatus; + + ShellStatus = SHELL_SUCCESS; + Private = AllocateZeroPool (sizeof (PING_PRIVATE_DATA)); + + if (Private == NULL) { + return (SHELL_OUT_OF_RESOURCES); + } + + Private->IpChoice = IpChoice; + Private->Signature = PING_PRIVATE_DATA_SIGNATURE; + Private->SendNum = SendNumber; + Private->BufferSize = BufferSize; + Private->RttMin = ~((UINT64 )(0x0)); + Private->Status = EFI_NOT_READY; + + CopyMem(&Private->SrcAddress, SrcAddress, sizeof(Private->SrcAddress)); + CopyMem(&Private->DstAddress, DstAddress, sizeof(Private->DstAddress)); + + InitializeListHead (&Private->TxList); + + // + // Open and configure a ip instance for us. + // + Status = PingCreateIpInstance (Private); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + // + // Print the command line itself. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_START), gShellNetwork1HiiHandle, mDstString, Private->BufferSize); + // + // Create a ipv6 token to receive the first icmp6 echo reply packet. + // + Status = Ping6ReceiveEchoReply (Private); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + // + // Create and start timer to send icmp6 echo request packet per second. + // + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + Ping6OnTimerRoutine, + Private, + &Private->Timer + ); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + // + // Start a timer to calculate the RTT. + // + Status = PingInitRttTimer (Private); + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + // + // Create a ipv6 token to send the first icmp6 echo request packet. + // + Status = PingSendEchoRequest (Private); + // + // EFI_NOT_READY for IPsec is enable and IKE is not established. + // + if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) { + ShellStatus = SHELL_ACCESS_DENIED; + if(Status == EFI_NOT_FOUND) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_NOSOURCE_INDO), gShellNetwork1HiiHandle, mDstString); + } else if (Status == RETURN_NO_MAPPING) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_NOROUTE_FOUND), gShellNetwork1HiiHandle, mDstString, mSrcString); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_NETWORK_ERROR), gShellNetwork1HiiHandle, L"ping", Status); + } + + goto ON_EXIT; + } + + Status = gBS->SetTimer ( + Private->Timer, + TimerPeriodic, + ONE_SECOND + ); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + // + // Control the ping6 process by two factors: + // 1. Hot key + // 2. Private->Status + // 2.1. success means all icmp6 echo request packets get reply packets. + // 2.2. timeout means the last icmp6 echo reply request timeout to get reply. + // 2.3. noready means ping6 process is on-the-go. + // + while (Private->Status == EFI_NOT_READY) { + Status = Private->ProtocolPointers.Poll (Private->IpProtocol); + if (ShellGetExecutionBreakFlag()) { + Private->Status = EFI_ABORTED; + goto ON_STAT; + } + } + +ON_STAT: + // + // Display the statistics in all. + // + gBS->SetTimer (Private->Timer, TimerCancel, 0); + + if (Private->TxCount != 0) { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_PING_STAT), + gShellNetwork1HiiHandle, + Private->TxCount, + (Private->RxCount - Private->FailedCount), + (100 - ((100 * (Private->RxCount - Private->FailedCount)) / Private->TxCount)), + Private->RttSum + ); + } + + if (Private->RxCount > Private->FailedCount) { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_PING_RTT), + gShellNetwork1HiiHandle, + Private->RttMin, + Private->RttMin + Private->TimerPeriod, + Private->RttMax, + Private->RttMax + Private->TimerPeriod, + DivU64x64Remainder (Private->RttSum, (Private->RxCount - Private->FailedCount), NULL), + DivU64x64Remainder (Private->RttSum, (Private->RxCount - Private->FailedCount), NULL) + Private->TimerPeriod + ); + } + +ON_EXIT: + + if (Private != NULL) { + + NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) { + TxInfo = BASE_CR (Entry, PING_ICMPX_TX_INFO, Link); + + if (Private->IpProtocol != NULL && Private->ProtocolPointers.Cancel != NULL) { + Status = Private->ProtocolPointers.Cancel (Private->IpProtocol, TxInfo->Token); + } + + RemoveEntryList (&TxInfo->Link); + PingDestroyTxInfo (TxInfo, Private->IpChoice); + } + + PingFreeRttTimer (Private); + + if (Private->Timer != NULL) { + gBS->CloseEvent (Private->Timer); + } + + if (Private->IpProtocol != NULL && Private->ProtocolPointers.Cancel != NULL) { + Status = Private->ProtocolPointers.Cancel (Private->IpProtocol, &Private->RxToken); + } + + if (Private->RxToken.Event != NULL) { + gBS->CloseEvent (Private->RxToken.Event); + } + + if (Private->IpChildHandle != NULL) { + Ping6DestroyIp6Instance (Private); + } + + FreePool (Private); + } + + return ShellStatus; +} + +/** + Function for 'ping' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). + + @retval SHELL_SUCCESS The ping processed successfullly. + @retval others The ping processed unsuccessfully. + +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunPing ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + EFI_IPv6_ADDRESS DstAddress; + EFI_IPv6_ADDRESS SrcAddress; + UINT64 BufferSize; + UINTN SendNumber; + LIST_ENTRY *ParamPackage; + CONST CHAR16 *ValueStr; + UINTN NonOptionCount; + UINT32 IpChoice; + CHAR16 *ProblemParam; + + // + // we use IPv6 buffers to hold items... + // make sure this is enough space! + // + ASSERT(sizeof(EFI_IPv4_ADDRESS ) <= sizeof(EFI_IPv6_ADDRESS )); + ASSERT(sizeof(EFI_IP4_COMPLETION_TOKEN) <= sizeof(EFI_IP6_COMPLETION_TOKEN )); + + IpChoice = PING_IP_CHOICE_IP4; + + ShellStatus = SHELL_SUCCESS; + ProblemParam = NULL; + + Status = ShellCommandLineParseEx (PingParamList, &ParamPackage, &ProblemParam, TRUE, FALSE); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + + if (ShellCommandLineGetFlag (ParamPackage, L"-_ip6")) { + IpChoice = PING_IP_CHOICE_IP6; + } + + // + // Parse the parameter of count number. + // + ValueStr = ShellCommandLineGetValue (ParamPackage, L"-n"); + if (ValueStr != NULL) { + SendNumber = ShellStrToUintn (ValueStr); + + // + // ShellStrToUintn will return 0 when input is 0 or an invalid input string. + // + if ((SendNumber == 0) || (SendNumber > MAX_SEND_NUMBER)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + } else { + SendNumber = DEFAULT_SEND_COUNT; + } + // + // Parse the parameter of buffer size. + // + ValueStr = ShellCommandLineGetValue (ParamPackage, L"-l"); + if (ValueStr != NULL) { + BufferSize = ShellStrToUintn (ValueStr); + + // + // ShellStrToUintn will return 0 when input is 0 or an invalid input string. + // + if ((BufferSize < 16) || (BufferSize > MAX_BUFFER_SIZE)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + } else { + BufferSize = DEFAULT_BUFFER_SIZE; + } + + ZeroMem (&SrcAddress, sizeof (EFI_IPv6_ADDRESS)); + ZeroMem (&DstAddress, sizeof (EFI_IPv6_ADDRESS)); + + // + // Parse the parameter of source ip address. + // + ValueStr = ShellCommandLineGetValue (ParamPackage, L"-s"); + if (ValueStr == NULL) { + ValueStr = ShellCommandLineGetValue (ParamPackage, L"-_s"); + } + + if (ValueStr != NULL) { + mSrcString = ValueStr; + if (IpChoice == PING_IP_CHOICE_IP6) { + Status = NetLibStrToIp6 (ValueStr, &SrcAddress); + } else { + Status = NetLibStrToIp4 (ValueStr, (EFI_IPv4_ADDRESS*)&SrcAddress); + } + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + } + // + // Parse the parameter of destination ip address. + // + NonOptionCount = ShellCommandLineGetCount(ParamPackage); + if (NonOptionCount < 2) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellNetwork1HiiHandle, L"ping"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + if (NonOptionCount > 2) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellNetwork1HiiHandle, L"ping"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + ValueStr = ShellCommandLineGetRawValue (ParamPackage, 1); + if (ValueStr != NULL) { + mDstString = ValueStr; + if (IpChoice == PING_IP_CHOICE_IP6) { + Status = NetLibStrToIp6 (ValueStr, &DstAddress); + } else { + Status = NetLibStrToIp4 (ValueStr, (EFI_IPv4_ADDRESS*)&DstAddress); + } + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + } + + // + // Enter into ping process. + // + ShellStatus = ShellPing ( + (UINT32)SendNumber, + (UINT32)BufferSize, + &SrcAddress, + &DstAddress, + IpChoice + ); + +ON_EXIT: + ShellCommandLineFreeVarList (ParamPackage); + return ShellStatus; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.c new file mode 100644 index 00000000..0861a424 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.c @@ -0,0 +1,84 @@ +/** @file + Main file for NULL named library for network1 shell command functions. + + Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "UefiShellNetwork1CommandsLib.h" + +CONST CHAR16 gShellNetwork1FileName[] = L"ShellCommands"; +EFI_HII_HANDLE gShellNetwork1HiiHandle = NULL; + +/** + return the file name of the help text file if not using HII. + + @return The string pointer to the file name. +**/ +CONST CHAR16* +EFIAPI +ShellCommandGetManFileNameNetwork1 ( + VOID + ) +{ + return (gShellNetwork1FileName); +} + +/** + Constructor for the Shell Network1 Commands library. + + Install the handlers for Network1 UEFI Shell 2.0 profile commands. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. + + @retval EFI_SUCCESS The shell command handlers were installed sucessfully. + @retval EFI_UNSUPPORTED The shell level required was not found. +**/ +EFI_STATUS +EFIAPI +ShellNetwork1CommandsLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + gShellNetwork1HiiHandle = NULL; + + // + // check our bit of the profiles mask + // + if ((PcdGet8(PcdShellProfileMask) & BIT3) == 0) { + return (EFI_SUCCESS); + } + + gShellNetwork1HiiHandle = HiiAddPackages (&gShellNetwork1HiiGuid, gImageHandle, UefiShellNetwork1CommandsLibStrings, NULL); + if (gShellNetwork1HiiHandle == NULL) { + return (EFI_DEVICE_ERROR); + } + // + // install our shell command handlers + // + ShellCommandRegisterCommandName(L"ping", ShellCommandRunPing , ShellCommandGetManFileNameNetwork1, 0, L"network1", TRUE , gShellNetwork1HiiHandle, STRING_TOKEN(STR_GET_HELP_PING)); + ShellCommandRegisterCommandName(L"ifconfig",ShellCommandRunIfconfig , ShellCommandGetManFileNameNetwork1, 0, L"network1", TRUE , gShellNetwork1HiiHandle, STRING_TOKEN(STR_GET_HELP_IFCONFIG)); + + return (EFI_SUCCESS); +} + +/** + Destructor for the library. free any resources. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. +**/ +EFI_STATUS +EFIAPI +ShellNetwork1CommandsLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + if (gShellNetwork1HiiHandle != NULL) { + HiiRemovePackages(gShellNetwork1HiiHandle); + } + return (EFI_SUCCESS); +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.h new file mode 100644 index 00000000..7db71f0f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.h @@ -0,0 +1,70 @@ +/** @file + header file for NULL named library for network1 shell command functions. + + Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _UEFI_SHELL_NETWORK1_COMMANDS_LIB_H_ +#define _UEFI_SHELL_NETWORK1_COMMANDS_LIB_H_ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern EFI_HII_HANDLE gShellNetwork1HiiHandle; + +/** + Function for 'ping' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunPing ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'ifconfig' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunIfconfig ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +#endif + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf new file mode 100644 index 00000000..87463707 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf @@ -0,0 +1,64 @@ +## @file +# Provides shell network1 functions +# +# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiShellNetwork1CommandsLib + FILE_GUID = 9A929F7E-3861-45ce-87AB-7371219AE255 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = ShellNetwork1CommandsLibConstructor + DESTRUCTOR = ShellNetwork1CommandsLibDestructor + +[Sources.common] + UefiShellNetwork1CommandsLib.uni + UefiShellNetwork1CommandsLib.c + UefiShellNetwork1CommandsLib.h + Ping.c + Ifconfig.c + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + NetworkPkg/NetworkPkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + ShellCommandLib + ShellLib + UefiLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + PcdLib + HiiLib + FileHandleLib + NetLib + +[Pcd] + gEfiShellPkgTokenSpaceGuid.PcdShellProfileMask ## CONSUMES + +[Protocols] + gEfiCpuArchProtocolGuid ## CONSUMES + gEfiTimerArchProtocolGuid ## CONSUMES + gEfiIp6ProtocolGuid ## SOMETIMES_CONSUMES + gEfiIp6ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES + gEfiIp6ConfigProtocolGuid ## SOMETIMES_CONSUMES + + gEfiIp4ProtocolGuid ## SOMETIMES_CONSUMES + gEfiIp4ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES + gEfiIp4Config2ProtocolGuid ## SOMETIMES_CONSUMES + +[Guids] + gShellNetwork1HiiGuid ## SOMETIMES_CONSUMES ## HII diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.uni b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.uni new file mode 100644 index 00000000..73cf96d9 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.uni @@ -0,0 +1,176 @@ +// /** +// +// (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
+// Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+// (C) Copyright 2017 Hewlett Packard Enterprise Development LP
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// Module Name: +// +// UefiShellNetwork1CommandsLib.uni +// +// Abstract: +// +// String definitions for UEFI Shell 2.0 network 1 commands +// +// +// **/ + +/=# + +#langdef en-US "english" + +#string STR_GEN_TOO_MANY #language en-US "%H%s%N: Too many arguments.\r\n" +#string STR_GEN_TOO_FEW #language en-US "%H%s%N: Too few arguments.\r\n" +#string STR_GEN_PARAM_INV #language en-US "%H%s%N: Invalid argument - '%H%s%N'\r\n" +#string STR_GEN_PROBLEM #language en-US "%H%s%N: Unknown flag - '%H%s%N'\r\n" +#string STR_GEN_PROBLEM_OP2 #language en-US "%H%s%N: Invalid argument - '%H%s%N'. Expected '%B%s%N' or '%B%s%N'.\r\n" +#string STR_GEN_PROBLEM_VAL #language en-US "%H%s%N: Bad value - '%H%s%N' for flag - '%H%s%N'\r\n" +#string STR_GEN_NO_VALUE #language en-US "%H%s%N: Missing argument for flag - '%H%s%N'\r\n" +#string STR_GEN_ERR_AD #language en-US "%H%s%N: Access denied.\r\n" +#string STR_GEN_ERR_UK #language en-US "%H%s%N: Status: %r\r\n" +#string STR_GEN_PARAM_CON #language en-US "%H%s%N: Parameters conflict.\r\n" +#string STR_GEN_FILE_OPEN_FAIL #language en-US "%H%s%N: Cannot open file - '%H%s%N'\r\n" +#string STR_GEN_FILE_AD #language en-US "%H%s%N: Access file error - '%H%s%N'\r\n" +#string STR_GEN_CRLF #language en-US "\r\n" +#string STR_GEN_NO_FILES #language en-US "%H%s%N: No matching files were found.\r\n" +#string STR_GEN_DIR_NF #language en-US "%H%s%N: Directory not found - '%H%s%N'\r\n" +#string STR_GEN_FILE_NF #language en-US "%H%s%N: File not found - '%H%s%N'\r\n" +#string STR_GEN_IS_DIR #language en-US "%H%s%N: '%H%s%N' is a directory\r\n" +#string STR_GEN_PROTOCOL_NF #language en-US "%H%s%N: The protocol '%H%s%N' is required and not found (%g).\r\n" +#string STR_GEN_OUT_MEM #language en-US "%H%s%N: Memory allocation was not successful.\r\n" + +#string STR_PING_INVALID_SOURCE #language en-US "%Ping: Require source interface option\r\n" +#string STR_PING_CONFIG #language en-US "Config %r\r\n" +#string STR_PING_GETMODE #language en-US "GetModeData %r\r\n" +#string STR_PING_GETDATA #language en-US "GetData %r\r\n" +#string STR_PING_RECEIVE #language en-US "Receive %r\r\n" +#string STR_PING_SEND_REQUEST #language en-US "Echo request sequence %d did not complete successfully.\r\n" +#string STR_PING_NOSOURCE_INDO #language en-US "There are no sources in %s's multicast domain.\r\n" +#string STR_PING_NETWORK_ERROR #language en-US "%H%s%N: Network function failed with %r\r\n" +#string STR_PING_CONFIGD_NIC_NF #language en-US "%H%s%N: No configured interfaces were found.\r\n" +#string STR_PING_NOROUTE_FOUND #language en-US "There is no route to the destination '%B%s%N' from the source '%B%s%N' was found.\r\n" +#string STR_PING_START #language en-US "Ping %s %d data bytes.\r\n" +#string STR_PING_TIMEOUT #language en-US "Echo request sequence %d timeout.\r\n" +#string STR_PING_REPLY_INFO #language en-US "%d bytes from %s : icmp_seq=%d ttl=%d time%d~%dms\r\n" +#string STR_PING_STAT #language en-US "\n%d packets transmitted, %d received, %d%% packet loss, time %dms\r\n" +#string STR_PING_RTT #language en-US "\nRtt(round trip time) min=%d~%dms max=%d~%dms avg=%d~%dms\r\n" + +#string STR_IFCONFIG_UNSUPPORTED_OPTION #language en-US "The option '%H%s%N' is unsupported now.\n" +#string STR_IFCONFIG_LACK_OPTION #language en-US "Flags lack. Please type 'ifConfig -?' for help info.\n" +#string STR_IFCONFIG_LACK_INTERFACE #language en-US "Lack interface name.\n" +#string STR_IFCONFIG_LACK_COMMAND #language en-US "Lack interface config option.\n" +#string STR_IFCONFIG_INVALID_INTERFACE #language en-US "Invalid interface name.\n" +#string STR_IFCONFIG_INVALID_IPADDRESS #language en-US "Invalid ipv4 address: '%H%s%N'\n" +#string STR_IFCONFIG_INVALID_GATEWAY #language en-US "Invalid gateway address: '%H%s%N'\n" +#string STR_IFCONFIG_DUPLICATE_COMMAND #language en-US "Duplicate commands. Bad command %H%s%N is skipped.\n" +#string STR_IFCONFIG_CONFLICT_COMMAND #language en-US "Conflict commands. Bad command %H%s%N is skipped.\n" +#string STR_IFCONFIG_UNKNOWN_COMMAND #language en-US "Unknown commands. Bad command %H%s%N is skipped.\n" +#string STR_IFCONFIG_SET_ADDR_FAILED #language en-US "Failed to set address.\n" +#string STR_IFCONFIG_ROUTES_SIZE #language en-US "\n%H Routes (%d entries):\n" +#string STR_IFCONFIG_ROUTES_ENTRY_INDEX #language en-US "%H Entry[%d]\n" +#string STR_IFCONFIG_SHOW_IP_ADDR #language en-US "%12s: %N%d.%d.%d.%d\n" +#string STR_IFCONFIG_INFO_NEWLINE #language en-US "\n" +#string STR_IFCONFIG_INFO_DNS_ADDR_BODY #language en-US "%8d.%d.%d.%d\n" +#string STR_IFCONFIG_INFO_BREAK #language en-US "\n-----------------------------------------------------------------\n" +#string STR_IFCONFIG_INFO_COLON #language en-US ":" +#string STR_IFCONFIG_INFO_IF_NAME #language en-US "\n%Hname : %s%N\n" +#string STR_IFCONFIG_INFO_MEDIA_STATE #language en-US "%HMedia State : %s%N\n" +#string STR_IFCONFIG_INFO_POLICY_DHCP #language en-US "%Hpolicy : dhcp%N\n" +#string STR_IFCONFIG_INFO_POLICY_MAN #language en-US "%Hpolicy : static%N\n" +#string STR_IFCONFIG_INFO_MAC_ADDR_HEAD #language en-US "%Hmac addr : %N" +#string STR_IFCONFIG_INFO_MAC_ADDR_BODY #language en-US "%02x" +#string STR_IFCONFIG_INFO_IP_ADDR_HEAD #language en-US "\n%Hipv4 address : %N" +#string STR_IFCONFIG_INFO_SUBNET_MASK_HEAD #language en-US "\n%Hsubnet mask : %N" +#string STR_IFCONFIG_INFO_GATEWAY_HEAD #language en-US "\n%Hdefault gateway: %N" +#string STR_IFCONFIG_INFO_DNS_ADDR_HEAD #language en-US "\n%HDNS server : %N\n" +#string STR_IFCONFIG_INFO_IP_ADDR_BODY #language en-US "%d.%d.%d.%d\n" + +#string STR_GET_HELP_PING #language en-US "" +".TH ping 0 "Ping the target host with an IPv4 stack."\r\n" +".SH NAME\r\n" +"Ping the target host with an IPv4 stack.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"PING [-n count] [-l size] [-s SourceIp] TargetIp\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -n - Specifies the number of echo request datagrams to be sent.\r\n" +" -l - Specifies the size of the data buffer in the echo request datagram.\r\n" +" -s - Specifies the source adapter as IPv4 address.\r\n" +" SourceIp - Specifies the IPv4 address of the source machine.\r\n" +" TargetIp - Specifies the IPv4 address of the target machine.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command uses the ICMPv4 ECHO_REQUEST datagram to elicit an\r\n" +" ECHO_REPLY from a host.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To ping the target host with 64 bytes data:\r\n" +" fs0:\> ping -l 64 192.168.0.1\r\n" +" \r\n" +" * To ping the target host by sending 20 echo request datagrams:\r\n" +" fs0:\> ping -n 20 202.120.100.1\r\n" +" \r\n" +" * To ping the target host by specifying the source adapter as IPv4 address:\r\n" +" fs0:\> ping -s 202.120.100.12 202.120.100.1\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_INVALID_PARAMETER One of the passed-in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" + +#string STR_GET_HELP_IFCONFIG #language en-US "" +".TH ifconfig 0 "Modifies the default IP address of the UEFI IPv4 Network Stack."\r\n" +".SH NAME\r\n" +"Modifies the default IP address of the UEFI IPv4 Network Stack.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"IFCONFIG [-r [Name]] [-l [Name]]\r\n" +"IFCONFIG [-s dhcp | > | >]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -r - Renew configuration of interface and set dhcp policy.\r\n" +" -l - Lists the configuration.\r\n" +" -s - Sets the configuration.\r\n" +" Name - Specifies an adapter name (for example, eth0).\r\n" +" IP - Specifies the IPv4 address in four integer values:\r\n" +" - Example: 192.168.0.10\r\n" +" SubnetMask - Specifies a subnet mask in four integer values:\r\n" +" - Example: 255.255.255.0\r\n" +" GatewayMask - Specifies a default gateway in four integer values:\r\n" +" - Example: 192.168.0.1\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. This command modifies the default IP address for the UEFI IPv4\r\n" +" network stack.\r\n" +" 2. Use '-r' to renew configuration of interface and set dhcp policy.\r\n" +" 3. Use '-l' to list the DNS and other address related settings for all\r\n" +" interfaces or the specified interface.\r\n" +" 4. Use '-s static ' with \r\n" +" static IPv4 address configuration for specified interface.\r\n" +" 5. Use '-s dhcp' for DHCPv4 to request the IPv4 address\r\n" +" configuration dynamically for specified interface.\r\n" +" 6. Use '-s dns ' must under manual policy.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To list the configuration for the eth0 interface:\r\n" +" fs0:\> ifconfig -l eth0\r\n" +" \r\n" +" * To use DHCPv4 to request the IPv4 address configuration dynamically for the\r\n" +" eth0 interface:\r\n" +" fs0:\> ifconfig -s eth0 dhcp\r\n" +" \r\n" +" * To use the static IPv4 address configuration for the eth0 interface:\r\n" +" fs0:\> ifconfig -s eth0 static 192.168.0.5 255.255.255.0 192.168.0.1\r\n" +" \r\n" +" * To configure DNS server address for the eth0 interface:\r\n" +" fs0:\> ifconfig -s eth0 dns 192.168.0.8 192.168.0.9\r\n" + + + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork2CommandsLib/Ifconfig6.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork2CommandsLib/Ifconfig6.c new file mode 100644 index 00000000..c5df13b3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork2CommandsLib/Ifconfig6.c @@ -0,0 +1,1906 @@ +/** @file + The implementation for Shell command IfConfig6. + + Copyright (c) 2016, Intel Corporation. All rights reserved.
+ (C) Copyright 2017 Hewlett Packard Enterprise Development LP
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "UefiShellNetwork2CommandsLib.h" + +enum { + IfConfig6OpList = 1, + IfConfig6OpSet = 2, + IfConfig6OpClear = 3 +}; + +typedef enum { + VarCheckReserved = -1, + VarCheckOk = 0, + VarCheckDuplicate, + VarCheckConflict, + VarCheckUnknown, + VarCheckLackValue, + VarCheckOutOfMem +} VAR_CHECK_CODE; + +typedef enum { + FlagTypeSingle = 0, + FlagTypeNeedVar, + FlagTypeNeedSet, + FlagTypeSkipUnknown +} VAR_CHECK_FLAG_TYPE; + +#define MACADDRMAXSIZE 32 +#define PREFIXMAXLEN 16 + +typedef struct _IFCONFIG6_INTERFACE_CB { + EFI_HANDLE NicHandle; + LIST_ENTRY Link; + EFI_IP6_CONFIG_PROTOCOL *IfCfg; + EFI_IP6_CONFIG_INTERFACE_INFO *IfInfo; + EFI_IP6_CONFIG_INTERFACE_ID *IfId; + EFI_IP6_CONFIG_POLICY Policy; + EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS Xmits; + UINT32 DnsCnt; + EFI_IPv6_ADDRESS DnsAddr[1]; +} IFCONFIG6_INTERFACE_CB; + +typedef struct _ARG_LIST ARG_LIST; + +struct _ARG_LIST { + ARG_LIST *Next; + CHAR16 *Arg; +}; + +typedef struct _IFCONFIG6_PRIVATE_DATA { + EFI_HANDLE ImageHandle; + LIST_ENTRY IfList; + + UINT32 OpCode; + CHAR16 *IfName; + ARG_LIST *VarArg; +} IFCONFIG6_PRIVATE_DATA; + +typedef struct _VAR_CHECK_ITEM{ + CHAR16 *FlagStr; + UINT32 FlagID; + UINT32 ConflictMask; + VAR_CHECK_FLAG_TYPE FlagType; +} VAR_CHECK_ITEM; + + +SHELL_PARAM_ITEM mIfConfig6CheckList[] = { + { + L"-b", + TypeFlag + }, + { + L"-s", + TypeMaxValue + }, + { + L"-l", + TypeValue + }, + { + L"-r", + TypeValue + }, + { + L"-?", + TypeFlag + }, + { + NULL, + TypeMax + }, +}; + +VAR_CHECK_ITEM mIfConfig6SetCheckList[] = { + { + L"auto", + 0x00000001, + 0x00000001, + FlagTypeSingle + }, + { + L"man", + 0x00000002, + 0x00000001, + FlagTypeSingle + }, + { + L"host", + 0x00000004, + 0x00000002, + FlagTypeSingle + }, + { + L"dad", + 0x00000008, + 0x00000004, + FlagTypeSingle + }, + { + L"gw", + 0x00000010, + 0x00000008, + FlagTypeSingle + }, + { + L"dns", + 0x00000020, + 0x00000010, + FlagTypeSingle + }, + { + L"id", + 0x00000040, + 0x00000020, + FlagTypeSingle + }, + { + NULL, + 0x0, + 0x0, + FlagTypeSkipUnknown + }, +}; + +/** + Free the ARG_LIST. + + @param List Pointer to ARG_LIST to free. +**/ +VOID +IfConfig6FreeArgList ( + ARG_LIST *List +) +{ + ARG_LIST *Next; + while (List->Next != NULL) { + Next = List->Next; + FreePool (List); + List = Next; + } + + FreePool (List); +} + +/** + Split a string with specified separator and save the substring to a list. + + @param[in] String The pointer of the input string. + @param[in] Separator The specified separator. + + @return The pointer of headnode of ARG_LIST. + +**/ +ARG_LIST * +IfConfig6SplitStrToList ( + IN CONST CHAR16 *String, + IN CHAR16 Separator + ) +{ + CHAR16 *Str; + CHAR16 *ArgStr; + ARG_LIST *ArgList; + ARG_LIST *ArgNode; + + if (String == NULL || *String == L'\0') { + return NULL; + } + + // + // Copy the CONST string to a local copy. + // + Str = AllocateCopyPool (StrSize (String), String); + if (Str == NULL) { + return NULL; + } + ArgStr = Str; + + // + // init a node for the list head. + // + ArgNode = (ARG_LIST *) AllocateZeroPool (sizeof (ARG_LIST)); + if (ArgNode == NULL) { + return NULL; + } + ArgList = ArgNode; + + // + // Split the local copy and save in the list node. + // + while (*Str != L'\0') { + if (*Str == Separator) { + *Str = L'\0'; + ArgNode->Arg = ArgStr; + ArgStr = Str + 1; + ArgNode->Next = (ARG_LIST *) AllocateZeroPool (sizeof (ARG_LIST)); + if (ArgNode->Next == NULL) { + // + // Free the local copy of string stored in the first node + // + FreePool (ArgList->Arg); + IfConfig6FreeArgList (ArgList); + return NULL; + } + ArgNode = ArgNode->Next; + } + + Str++; + } + + ArgNode->Arg = ArgStr; + ArgNode->Next = NULL; + + return ArgList; +} + +/** + Check the correctness of input Args with '-s' option. + + @param[in] CheckList The pointer of VAR_CHECK_ITEM array. + @param[in] Name The pointer of input arg. + @param[in] Init The switch to execute the check. + + @return The value of VAR_CHECK_CODE. + +**/ +VAR_CHECK_CODE +IfConfig6RetriveCheckListByName( + IN VAR_CHECK_ITEM *CheckList, + IN CHAR16 *Name, + IN BOOLEAN Init +) +{ + STATIC UINT32 CheckDuplicate; + STATIC UINT32 CheckConflict; + VAR_CHECK_CODE RtCode; + UINT32 Index; + VAR_CHECK_ITEM Arg; + + if (Init) { + CheckDuplicate = 0; + CheckConflict = 0; + return VarCheckOk; + } + + RtCode = VarCheckOk; + Index = 0; + Arg = CheckList[Index]; + + // + // Check the Duplicated/Conflicted/Unknown input Args. + // + while (Arg.FlagStr != NULL) { + if (StrCmp (Arg.FlagStr, Name) == 0) { + + if (CheckDuplicate & Arg.FlagID) { + RtCode = VarCheckDuplicate; + break; + } + + if (CheckConflict & Arg.ConflictMask) { + RtCode = VarCheckConflict; + break; + } + + CheckDuplicate |= Arg.FlagID; + CheckConflict |= Arg.ConflictMask; + break; + } + + Arg = CheckList[++Index]; + } + + if (Arg.FlagStr == NULL) { + RtCode = VarCheckUnknown; + } + + return RtCode; +} + +/** + The notify function of create event when performing a manual config. + + @param[in] Event The event this notify function registered to. + @param[in] Context Pointer to the context data registered to the event. + +**/ +VOID +EFIAPI +IfConfig6ManualAddressNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + *((BOOLEAN *) Context) = TRUE; +} + +/** + Print MAC address. + + @param[in] Node The pointer of MAC address buffer. + @param[in] Size The size of MAC address buffer. + +**/ +VOID +IfConfig6PrintMacAddr ( + IN UINT8 *Node, + IN UINT32 Size + ) +{ + UINTN Index; + + ASSERT (Size <= MACADDRMAXSIZE); + + for (Index = 0; Index < Size; Index++) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_MAC_ADDR_BODY), gShellNetwork2HiiHandle, Node[Index]); + if (Index + 1 < Size) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_COLON), gShellNetwork2HiiHandle); + } + } + + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_NEWLINE), gShellNetwork2HiiHandle); +} + +/** + Print IPv6 address. + + @param[in] Ip The pointer of Ip bufffer in EFI_IPv6_ADDRESS format. + @param[in] PrefixLen The pointer of PrefixLen that describes the size Prefix. + +**/ +VOID +IfConfig6PrintIpAddr ( + IN EFI_IPv6_ADDRESS *Ip, + IN UINT8 *PrefixLen + ) +{ + UINTN Index; + BOOLEAN Short; + + Short = FALSE; + + for (Index = 0; Index < PREFIXMAXLEN; Index = Index + 2) { + + if (!Short && (Index + 1 < PREFIXMAXLEN) && (Index % 2 == 0) && (Ip->Addr[Index] == 0) && (Ip->Addr[Index + 1] == 0)) { + // + // Deal with the case of ::. + // + if (Index == 0) { + // + // :: is at the beginning of the address. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_COLON), gShellNetwork2HiiHandle); + } + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_COLON), gShellNetwork2HiiHandle); + + while ((Ip->Addr[Index] == 0) && (Ip->Addr[Index + 1] == 0) && (Index < PREFIXMAXLEN)) { + Index = Index + 2; + if (Index > PREFIXMAXLEN - 2) { + break; + } + } + + Short = TRUE; + + if (Index == PREFIXMAXLEN) { + // + // :: is at the end of the address. + // + break; + } + } + + if (Index < PREFIXMAXLEN - 1) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_IP_ADDR_BODY), gShellNetwork2HiiHandle, Ip->Addr[Index]); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_IP_ADDR_BODY), gShellNetwork2HiiHandle, Ip->Addr[Index + 1]); + } + + if (Index + 2 < PREFIXMAXLEN) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_COLON), gShellNetwork2HiiHandle); + } + } + + if (PrefixLen != NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_PREFIX_LEN), gShellNetwork2HiiHandle, *PrefixLen); + } +} + +/** + Pick up host IPv6 address in string format from Args with "-s" option and convert it to EFI_IP6_CONFIG_MANUAL_ADDRESS format. + + @param[in, out] Arg The pointer of the address of ARG_LIST which save Args with the "-s" option. + @param[out] Buf The pointer of the address of EFI_IP6_CONFIG_MANUAL_ADDRESS. + @param[out] BufSize The pointer of BufSize that describes the size of Buf in bytes. + + @retval EFI_SUCCESS The convertion is successful. + @retval Others Does't find the host address, or it is an invalid IPv6 address in string format. + +**/ +EFI_STATUS +IfConfig6ParseManualAddressList ( + IN OUT ARG_LIST **Arg, + OUT EFI_IP6_CONFIG_MANUAL_ADDRESS **Buf, + OUT UINTN *BufSize + ) +{ + EFI_STATUS Status; + EFI_IP6_CONFIG_MANUAL_ADDRESS *AddrBuf; + ARG_LIST *VarArg; + EFI_IPv6_ADDRESS Address; + UINT8 Prefix; + UINT8 AddrCnt; + + Prefix = 0; + AddrCnt = 0; + *BufSize = 0; + *Buf = NULL; + VarArg = *Arg; + Status = EFI_SUCCESS; + + // + // Go through the list to check the correctness of input host ip6 address. + // + while ((!EFI_ERROR (Status)) && (VarArg != NULL)) { + + Status = NetLibStrToIp6andPrefix (VarArg->Arg, &Address, &Prefix); + + if (EFI_ERROR (Status)) { + // + // host ip ip ... gw + // + break; + } + + VarArg = VarArg->Next; + AddrCnt++; + } + + if (AddrCnt == 0) { + return EFI_INVALID_PARAMETER; + } + + AddrBuf = AllocateZeroPool (AddrCnt * sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS)); + ASSERT (AddrBuf != NULL); + + AddrCnt = 0; + VarArg = *Arg; + Status = EFI_SUCCESS; + + // + // Go through the list to fill in the EFI_IP6_CONFIG_MANUAL_ADDRESS structure. + // + while ((!EFI_ERROR (Status)) && (VarArg != NULL)) { + + Status = NetLibStrToIp6andPrefix (VarArg->Arg, &Address, &Prefix); + + if (EFI_ERROR (Status)) { + break; + } + + // + // If prefix length is not set, set it as Zero here. In the IfConfigSetInterfaceInfo() + // Zero prefix, length will be transfered to default prefix length. + // + if (Prefix == 0xFF) { + Prefix = 0; + } + AddrBuf[AddrCnt].IsAnycast = FALSE; + AddrBuf[AddrCnt].PrefixLength = Prefix; + IP6_COPY_ADDRESS (&AddrBuf[AddrCnt].Address, &Address); + VarArg = VarArg->Next; + AddrCnt++; + } + + *Arg = VarArg; + + if (EFI_ERROR (Status) && (Status != EFI_INVALID_PARAMETER)) { + goto ON_ERROR; + } + + *Buf = AddrBuf; + *BufSize = AddrCnt * sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS); + + return EFI_SUCCESS; + +ON_ERROR: + + FreePool (AddrBuf); + return Status; +} + +/** + Pick up gw/dns IPv6 address in string format from Args with "-s" option and convert it to EFI_IPv6_ADDRESS format. + + @param[in, out] Arg The pointer of the address of ARG_LIST that save Args with the "-s" option. + @param[out] Buf The pointer of the address of EFI_IPv6_ADDRESS. + @param[out] BufSize The pointer of BufSize that describes the size of Buf in bytes. + + @retval EFI_SUCCESS The conversion is successful. + @retval Others Doesn't find the host address, or it is an invalid IPv6 address in string format. + +**/ +EFI_STATUS +IfConfig6ParseGwDnsAddressList ( + IN OUT ARG_LIST **Arg, + OUT EFI_IPv6_ADDRESS **Buf, + OUT UINTN *BufSize + ) +{ + EFI_STATUS Status; + EFI_IPv6_ADDRESS *AddrBuf; + ARG_LIST *VarArg; + EFI_IPv6_ADDRESS Address; + UINT8 Prefix; + UINT8 AddrCnt; + + AddrCnt = 0; + *BufSize = 0; + *Buf = NULL; + VarArg = *Arg; + Status = EFI_SUCCESS; + + // + // Go through the list to check the correctness of input gw/dns address. + // + while ((!EFI_ERROR (Status)) && (VarArg != NULL)) { + + Status = NetLibStrToIp6andPrefix (VarArg->Arg, &Address, &Prefix); + + if (EFI_ERROR (Status)) { + // + // gw ip ip ... host + // + break; + } + + VarArg = VarArg->Next; + AddrCnt++; + } + + if (AddrCnt == 0) { + return EFI_INVALID_PARAMETER; + } + + AddrBuf = AllocateZeroPool (AddrCnt * sizeof (EFI_IPv6_ADDRESS)); + ASSERT (AddrBuf != NULL); + + AddrCnt = 0; + VarArg = *Arg; + Status = EFI_SUCCESS; + + // + // Go through the list to fill in the EFI_IPv6_ADDRESS structure. + // + while ((!EFI_ERROR (Status)) && (VarArg != NULL)) { + + Status = NetLibStrToIp6andPrefix (VarArg->Arg, &Address, &Prefix); + + if (EFI_ERROR (Status)) { + break; + } + + IP6_COPY_ADDRESS (&AddrBuf[AddrCnt], &Address); + + VarArg = VarArg->Next; + AddrCnt++; + } + + *Arg = VarArg; + + if (EFI_ERROR (Status) && (Status != EFI_INVALID_PARAMETER)) { + goto ON_ERROR; + } + + *Buf = AddrBuf; + *BufSize = AddrCnt * sizeof (EFI_IPv6_ADDRESS); + + return EFI_SUCCESS; + +ON_ERROR: + + FreePool (AddrBuf); + return Status; +} + +/** + Parse InterfaceId in string format from Args with the "-s" option and convert it to EFI_IP6_CONFIG_INTERFACE_ID format. + + @param[in, out] Arg The pointer of the address of ARG_LIST that saves Args with the "-s" option. + @param[out] IfId The pointer of EFI_IP6_CONFIG_INTERFACE_ID. + + @retval EFI_SUCCESS The get status processed successfullly. + @retval EFI_INVALID_PARAMETER The get status process failed. + +**/ +EFI_STATUS +IfConfig6ParseInterfaceId ( + IN OUT ARG_LIST **Arg, + OUT EFI_IP6_CONFIG_INTERFACE_ID **IfId + ) +{ + UINT8 Index; + UINT8 NodeVal; + CHAR16 *IdStr; + + if (*Arg == NULL) { + return EFI_INVALID_PARAMETER; + } + + Index = 0; + IdStr = (*Arg)->Arg; + ASSERT (IfId != NULL); + *IfId = AllocateZeroPool (sizeof (EFI_IP6_CONFIG_INTERFACE_ID)); + ASSERT (*IfId != NULL); + + while ((*IdStr != L'\0') && (Index < 8)) { + + NodeVal = 0; + while ((*IdStr != L':') && (*IdStr != L'\0')) { + + if ((*IdStr <= L'F') && (*IdStr >= L'A')) { + NodeVal = (UINT8)((NodeVal << 4) + *IdStr - L'A' + 10); + } else if ((*IdStr <= L'f') && (*IdStr >= L'a')) { + NodeVal = (UINT8)((NodeVal << 4) + *IdStr - L'a' + 10); + } else if ((*IdStr <= L'9') && (*IdStr >= L'0')) { + NodeVal = (UINT8)((NodeVal << 4) + *IdStr - L'0'); + } else { + FreePool (*IfId); + return EFI_INVALID_PARAMETER; + } + + IdStr++; + } + + (*IfId)->Id[Index++] = NodeVal; + + if (*IdStr == L':') { + IdStr++; + } + } + + *Arg = (*Arg)->Next; + return EFI_SUCCESS; +} + +/** + Parse dad in string format from Args with the "-s" option and convert it to UINT32 format. + + @param[in, out] Arg The pointer of the address of ARG_LIST that saves Args with the "-s" option. + @param[out] Xmits The pointer of Xmits. + + @retval EFI_SUCCESS The get status processed successfully. + @retval others The get status process failed. + +**/ +EFI_STATUS +IfConfig6ParseDadXmits ( + IN OUT ARG_LIST **Arg, + OUT UINT32 *Xmits + ) +{ + CHAR16 *ValStr; + + if (*Arg == NULL) { + return EFI_INVALID_PARAMETER; + } + + ValStr = (*Arg)->Arg; + *Xmits = 0; + + while (*ValStr != L'\0') { + + if ((*ValStr <= L'9') && (*ValStr >= L'0')) { + + *Xmits = (*Xmits * 10) + (*ValStr - L'0'); + + } else { + + return EFI_INVALID_PARAMETER; + } + + ValStr++; + } + + *Arg = (*Arg)->Next; + return EFI_SUCCESS; +} + +/** + The get current status of all handles. + + @param[in] ImageHandle The handle of ImageHandle. + @param[in] IfName The pointer of IfName(interface name). + @param[in] IfList The pointer of IfList(interface list). + + @retval EFI_SUCCESS The get status processed successfully. + @retval others The get status process failed. + +**/ +EFI_STATUS +IfConfig6GetInterfaceInfo ( + IN EFI_HANDLE ImageHandle, + IN CHAR16 *IfName, + IN LIST_ENTRY *IfList + ) +{ + EFI_STATUS Status; + UINTN HandleIndex; + UINTN HandleNum; + EFI_HANDLE *HandleBuffer; + EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg; + EFI_IP6_CONFIG_INTERFACE_INFO *IfInfo; + IFCONFIG6_INTERFACE_CB *IfCb; + UINTN DataSize; + + HandleBuffer = NULL; + HandleNum = 0; + + IfInfo = NULL; + IfCb = NULL; + + // + // Locate all the handles with ip6 service binding protocol. + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiIp6ServiceBindingProtocolGuid, + NULL, + &HandleNum, + &HandleBuffer + ); + if (EFI_ERROR (Status) || (HandleNum == 0)) { + return Status; + } + + // + // Enumerate all handles that installed with ip6 service binding protocol. + // + for (HandleIndex = 0; HandleIndex < HandleNum; HandleIndex++) { + IfCb = NULL; + IfInfo = NULL; + DataSize = 0; + + // + // Ip6config protocol and ip6 service binding protocol are installed + // on the same handle. + // + ASSERT (HandleBuffer != NULL); + Status = gBS->HandleProtocol ( + HandleBuffer[HandleIndex], + &gEfiIp6ConfigProtocolGuid, + (VOID **) &Ip6Cfg + ); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + // + // Get the interface information size. + // + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeInterfaceInfo, + &DataSize, + NULL + ); + + if (Status != EFI_BUFFER_TOO_SMALL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status); + goto ON_ERROR; + } + + IfInfo = AllocateZeroPool (DataSize); + + if (IfInfo == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + // + // Get the interface info. + // + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeInterfaceInfo, + &DataSize, + IfInfo + ); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status); + goto ON_ERROR; + } + // + // Check the interface name if required. + // + if ((IfName != NULL) && (StrCmp (IfName, IfInfo->Name) != 0)) { + FreePool (IfInfo); + continue; + } + + DataSize = 0; + // + // Get the size of dns server list. + // + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeDnsServer, + &DataSize, + NULL + ); + + if ((Status != EFI_BUFFER_TOO_SMALL) && (Status != EFI_NOT_FOUND)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status); + goto ON_ERROR; + } + + IfCb = AllocateZeroPool (sizeof (IFCONFIG6_INTERFACE_CB) + DataSize); + + if (IfCb == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + + IfCb->NicHandle = HandleBuffer[HandleIndex]; + IfCb->IfInfo = IfInfo; + IfCb->IfCfg = Ip6Cfg; + IfCb->DnsCnt = (UINT32) (DataSize / sizeof (EFI_IPv6_ADDRESS)); + + // + // Get the dns server list if has. + // + if (DataSize > 0) { + + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeDnsServer, + &DataSize, + IfCb->DnsAddr + ); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status); + goto ON_ERROR; + } + } + // + // Get the interface id if has. + // + DataSize = sizeof (EFI_IP6_CONFIG_INTERFACE_ID); + IfCb->IfId = AllocateZeroPool (DataSize); + + if (IfCb->IfId == NULL) { + goto ON_ERROR; + } + + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeAltInterfaceId, + &DataSize, + IfCb->IfId + ); + + if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status); + goto ON_ERROR; + } + + if (Status == EFI_NOT_FOUND) { + FreePool (IfCb->IfId); + IfCb->IfId = NULL; + } + // + // Get the config policy. + // + DataSize = sizeof (EFI_IP6_CONFIG_POLICY); + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypePolicy, + &DataSize, + &IfCb->Policy + ); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status); + goto ON_ERROR; + } + // + // Get the dad transmits. + // + DataSize = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS); + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeDupAddrDetectTransmits, + &DataSize, + &IfCb->Xmits + ); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status); + goto ON_ERROR; + } + + InsertTailList (IfList, &IfCb->Link); + + if ((IfName != NULL) && (StrCmp (IfName, IfInfo->Name) == 0)) { + // + // Only need the appointed interface, keep the allocated buffer. + // + IfCb = NULL; + IfInfo = NULL; + break; + } + } + + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + + return EFI_SUCCESS; + +ON_ERROR: + + if (IfInfo != NULL) { + FreePool (IfInfo); + } + + if (IfCb != NULL) { + if (IfCb->IfId != NULL) { + FreePool (IfCb->IfId); + } + + FreePool (IfCb); + } + + return Status; +} + +/** + The list process of the IfConfig6 application. + + @param[in] IfList The pointer of IfList(interface list). + + @retval SHELL_SUCCESS The IfConfig6 list processed successfully. + @retval others The IfConfig6 list process failed. + +**/ +SHELL_STATUS +IfConfig6ShowInterfaceInfo ( + IN LIST_ENTRY *IfList + ) +{ + LIST_ENTRY *Entry; + IFCONFIG6_INTERFACE_CB *IfCb; + UINTN Index; + + Entry = IfList->ForwardLink; + + if (IsListEmpty (IfList)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_INVALID_INTERFACE), gShellNetwork2HiiHandle); + } + + // + // Go through the interface list. + // + while (Entry != IfList) { + + IfCb = BASE_CR (Entry, IFCONFIG6_INTERFACE_CB, Link); + + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_BREAK), gShellNetwork2HiiHandle); + + // + // Print interface name. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_IF_NAME), gShellNetwork2HiiHandle, IfCb->IfInfo->Name); + + // + // Print interface config policy. + // + if (IfCb->Policy == Ip6ConfigPolicyAutomatic) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_POLICY_AUTO), gShellNetwork2HiiHandle); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_POLICY_MAN), gShellNetwork2HiiHandle); + } + + // + // Print dad transmit. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_DAD_TRANSMITS), gShellNetwork2HiiHandle, IfCb->Xmits); + + // + // Print interface id if has. + // + if (IfCb->IfId != NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_INTERFACE_ID_HEAD), gShellNetwork2HiiHandle); + + IfConfig6PrintMacAddr ( + IfCb->IfId->Id, + 8 + ); + } + // + // Print mac address of the interface. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_MAC_ADDR_HEAD), gShellNetwork2HiiHandle); + + IfConfig6PrintMacAddr ( + IfCb->IfInfo->HwAddress.Addr, + IfCb->IfInfo->HwAddressSize + ); + + // + // Print ip addresses list of the interface. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_IP_ADDR_HEAD), gShellNetwork2HiiHandle); + + for (Index = 0; Index < IfCb->IfInfo->AddressInfoCount; Index++) { + IfConfig6PrintIpAddr ( + &IfCb->IfInfo->AddressInfo[Index].Address, + &IfCb->IfInfo->AddressInfo[Index].PrefixLength + ); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_NEWLINE), gShellNetwork2HiiHandle); + } + + // + // Print dns server addresses list of the interface if has. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_DNS_ADDR_HEAD), gShellNetwork2HiiHandle); + + for (Index = 0; Index < IfCb->DnsCnt; Index++) { + IfConfig6PrintIpAddr ( + &IfCb->DnsAddr[Index], + NULL + ); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_NEWLINE), gShellNetwork2HiiHandle); + } + + // + // Print route table of the interface if has. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_ROUTE_HEAD), gShellNetwork2HiiHandle); + + for (Index = 0; Index < IfCb->IfInfo->RouteCount; Index++) { + IfConfig6PrintIpAddr ( + &IfCb->IfInfo->RouteTable[Index].Destination, + &IfCb->IfInfo->RouteTable[Index].PrefixLength + ); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_JOINT), gShellNetwork2HiiHandle); + + IfConfig6PrintIpAddr ( + &IfCb->IfInfo->RouteTable[Index].Gateway, + NULL + ); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_NEWLINE), gShellNetwork2HiiHandle); + } + + Entry = Entry->ForwardLink; + } + + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_BREAK), gShellNetwork2HiiHandle); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_NEWLINE), gShellNetwork2HiiHandle); + + return SHELL_SUCCESS; +} + +/** + The clean process of the IfConfig6 application. + + @param[in] IfList The pointer of IfList(interface list). + @param[in] IfName The pointer of interface name. + + @retval SHELL_SUCCESS The IfConfig6 clean processed successfully. + @retval others The IfConfig6 clean process failed. + +**/ +SHELL_STATUS +IfConfig6ClearInterfaceInfo ( + IN LIST_ENTRY *IfList, + IN CHAR16 *IfName + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + LIST_ENTRY *Entry; + IFCONFIG6_INTERFACE_CB *IfCb; + EFI_IP6_CONFIG_POLICY Policy; + + Entry = IfList->ForwardLink; + Status = EFI_SUCCESS; + ShellStatus = SHELL_SUCCESS; + + if (IsListEmpty (IfList)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_INVALID_INTERFACE), gShellNetwork2HiiHandle); + } + + // + // Go through the interface list.If the interface name is specified, then + // need to refresh the configuration. + // + while (Entry != IfList) { + + IfCb = BASE_CR (Entry, IFCONFIG6_INTERFACE_CB, Link); + + if ((IfName != NULL) && (StrCmp (IfName, IfCb->IfInfo->Name) == 0)) { + Policy = Ip6ConfigPolicyManual; + + Status = IfCb->IfCfg->SetData ( + IfCb->IfCfg, + Ip6ConfigDataTypePolicy, + sizeof (EFI_IP6_CONFIG_POLICY), + &Policy + ); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellNetwork2HiiHandle, L"ifconfig6"); + ShellStatus = SHELL_ACCESS_DENIED; + break; + } + } + + Policy = Ip6ConfigPolicyAutomatic; + + Status = IfCb->IfCfg->SetData ( + IfCb->IfCfg, + Ip6ConfigDataTypePolicy, + sizeof (EFI_IP6_CONFIG_POLICY), + &Policy + ); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellNetwork2HiiHandle, L"ifconfig6"); + ShellStatus = SHELL_ACCESS_DENIED; + break; + } + + Entry = Entry->ForwardLink; + } + + return ShellStatus; +} + +/** + The set process of the IfConfig6 application. + + @param[in] IfList The pointer of IfList(interface list). + @param[in] VarArg The pointer of ARG_LIST(Args with "-s" option). + + @retval SHELL_SUCCESS The IfConfig6 set processed successfully. + @retval others The IfConfig6 set process failed. + +**/ +SHELL_STATUS +IfConfig6SetInterfaceInfo ( + IN LIST_ENTRY *IfList, + IN ARG_LIST *VarArg + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + IFCONFIG6_INTERFACE_CB *IfCb; + EFI_IP6_CONFIG_MANUAL_ADDRESS *CfgManAddr; + EFI_IPv6_ADDRESS *CfgAddr; + UINTN AddrSize; + EFI_IP6_CONFIG_INTERFACE_ID *InterfaceId; + UINT32 DadXmits; + UINT32 CurDadXmits; + UINTN CurDadXmitsLen; + EFI_IP6_CONFIG_POLICY Policy; + + VAR_CHECK_CODE CheckCode; + EFI_EVENT TimeOutEvt; + EFI_EVENT MappedEvt; + BOOLEAN IsAddressOk; + + UINTN DataSize; + UINT32 Index; + UINT32 Index2; + BOOLEAN IsAddressSet; + EFI_IP6_CONFIG_INTERFACE_INFO *IfInfo; + + CfgManAddr = NULL; + CfgAddr = NULL; + TimeOutEvt = NULL; + MappedEvt = NULL; + IfInfo = NULL; + InterfaceId = NULL; + CurDadXmits = 0; + + if (IsListEmpty (IfList)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_INVALID_INTERFACE), gShellNetwork2HiiHandle); + return SHELL_INVALID_PARAMETER; + } + // + // Make sure to set only one interface each time. + // + IfCb = BASE_CR (IfList->ForwardLink, IFCONFIG6_INTERFACE_CB, Link); + Status = EFI_SUCCESS; + ShellStatus = SHELL_SUCCESS; + + // + // Initialize check list mechanism. + // + CheckCode = IfConfig6RetriveCheckListByName( + NULL, + NULL, + TRUE + ); + + // + // Create events & timers for asynchronous settings. + // + Status = gBS->CreateEvent ( + EVT_TIMER, + TPL_CALLBACK, + NULL, + NULL, + &TimeOutEvt + ); + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + IfConfig6ManualAddressNotify, + &IsAddressOk, + &MappedEvt + ); + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + // + // Parse the setting variables. + // + while (VarArg != NULL) { + // + // Check invalid parameters (duplication & unknown & conflict). + // + CheckCode = IfConfig6RetriveCheckListByName( + mIfConfig6SetCheckList, + VarArg->Arg, + FALSE + ); + + if (VarCheckOk != CheckCode) { + switch (CheckCode) { + case VarCheckDuplicate: + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_DUPLICATE_COMMAND), gShellNetwork2HiiHandle, VarArg->Arg); + break; + + case VarCheckConflict: + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_CONFLICT_COMMAND), gShellNetwork2HiiHandle, VarArg->Arg); + break; + + case VarCheckUnknown: + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_UNKNOWN_COMMAND), gShellNetwork2HiiHandle, VarArg->Arg); + break; + + default: + break; + } + + VarArg = VarArg->Next; + continue; + } + // + // Process valid variables. + // + if (StrCmp(VarArg->Arg, L"auto") == 0) { + // + // Set automaic config policy + // + Policy = Ip6ConfigPolicyAutomatic; + Status = IfCb->IfCfg->SetData ( + IfCb->IfCfg, + Ip6ConfigDataTypePolicy, + sizeof (EFI_IP6_CONFIG_POLICY), + &Policy + ); + + if (EFI_ERROR(Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + VarArg= VarArg->Next; + + if (VarArg != NULL) { + if (StrCmp (VarArg->Arg, L"host") == 0) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_INVALID_IP_CONFIG), gShellNetwork2HiiHandle, Status); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } else if (StrCmp (VarArg->Arg, L"gw") == 0) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_INVALID_GW_CONFIG), gShellNetwork2HiiHandle, Status); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } else if (StrCmp (VarArg->Arg, L"dns") == 0) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_INVALID_DNS_CONFIG), gShellNetwork2HiiHandle, Status); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + } + } else if (StrCmp (VarArg->Arg, L"man") == 0) { + // + // Set manual config policy. + // + Policy = Ip6ConfigPolicyManual; + Status = IfCb->IfCfg->SetData ( + IfCb->IfCfg, + Ip6ConfigDataTypePolicy, + sizeof (EFI_IP6_CONFIG_POLICY), + &Policy + ); + + if (EFI_ERROR(Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + VarArg= VarArg->Next; + + } else if (StrCmp (VarArg->Arg, L"host") == 0) { + // + // Parse till the next tag or the end of command line. + // + VarArg = VarArg->Next; + Status = IfConfig6ParseManualAddressList ( + &VarArg, + &CfgManAddr, + &AddrSize + ); + + if (EFI_ERROR (Status)) { + if (Status == EFI_INVALID_PARAMETER) { + ShellStatus = SHELL_INVALID_PARAMETER; + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_LACK_ARGUMENTS), gShellNetwork2HiiHandle, L"host"); + continue; + } else { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + } + // + // Set static host ip6 address list. + // This is a asynchronous process. + // + IsAddressOk = FALSE; + + Status = IfCb->IfCfg->RegisterDataNotify ( + IfCb->IfCfg, + Ip6ConfigDataTypeManualAddress, + MappedEvt + ); + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + Status = IfCb->IfCfg->SetData ( + IfCb->IfCfg, + Ip6ConfigDataTypeManualAddress, + AddrSize, + CfgManAddr + ); + + if (Status == EFI_NOT_READY) { + // + // Get current dad transmits count. + // + CurDadXmitsLen = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS); + IfCb->IfCfg->GetData ( + IfCb->IfCfg, + Ip6ConfigDataTypeDupAddrDetectTransmits, + &CurDadXmitsLen, + &CurDadXmits + ); + + gBS->SetTimer (TimeOutEvt, TimerRelative, 50000000 + 10000000 * CurDadXmits); + + while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) { + if (IsAddressOk) { + Status = EFI_SUCCESS; + break; + } + } + } + + IfCb->IfCfg->UnregisterDataNotify ( + IfCb->IfCfg, + Ip6ConfigDataTypeManualAddress, + MappedEvt + ); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_MAN_HOST), gShellNetwork2HiiHandle, Status); + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + // + // Check whether the address is set successfully. + // + DataSize = 0; + + Status = IfCb->IfCfg->GetData ( + IfCb->IfCfg, + Ip6ConfigDataTypeInterfaceInfo, + &DataSize, + NULL + ); + + if (Status != EFI_BUFFER_TOO_SMALL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status); + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + IfInfo = AllocateZeroPool (DataSize); + + if (IfInfo == NULL) { + ShellStatus = SHELL_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + Status = IfCb->IfCfg->GetData ( + IfCb->IfCfg, + Ip6ConfigDataTypeInterfaceInfo, + &DataSize, + IfInfo + ); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status); + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + for ( Index = 0; Index < (UINTN) (AddrSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS)); Index++) { + IsAddressSet = FALSE; + // + // By default, the prefix length 0 is regarded as 64. + // + if (CfgManAddr[Index].PrefixLength == 0) { + CfgManAddr[Index].PrefixLength = 64; + } + + for (Index2 = 0; Index2 < IfInfo->AddressInfoCount; Index2++) { + if (EFI_IP6_EQUAL (&IfInfo->AddressInfo[Index2].Address, &CfgManAddr[Index].Address) && + (IfInfo->AddressInfo[Index2].PrefixLength == CfgManAddr[Index].PrefixLength)) { + IsAddressSet = TRUE; + break; + } + } + + if (!IsAddressSet) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_ADDRESS_FAILED), gShellNetwork2HiiHandle); + IfConfig6PrintIpAddr ( + &CfgManAddr[Index].Address, + &CfgManAddr[Index].PrefixLength + ); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_NEWLINE), gShellNetwork2HiiHandle); + } + } + + } else if (StrCmp (VarArg->Arg, L"gw") == 0) { + // + // Parse till the next tag or the end of command line. + // + VarArg = VarArg->Next; + Status = IfConfig6ParseGwDnsAddressList ( + &VarArg, + &CfgAddr, + &AddrSize + ); + + if (EFI_ERROR (Status)) { + if (Status == EFI_INVALID_PARAMETER) { + ShellStatus = SHELL_INVALID_PARAMETER; + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_LACK_ARGUMENTS), gShellNetwork2HiiHandle, L"gw"); + continue; + } else { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + } + // + // Set static gateway ip6 address list. + // + Status = IfCb->IfCfg->SetData ( + IfCb->IfCfg, + Ip6ConfigDataTypeGateway, + AddrSize, + CfgAddr + ); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_MAN_GW), gShellNetwork2HiiHandle, Status); + goto ON_EXIT; + } + + } else if (StrCmp (VarArg->Arg, L"dns") == 0) { + // + // Parse till the next tag or the end of command line. + // + VarArg = VarArg->Next; + Status = IfConfig6ParseGwDnsAddressList ( + &VarArg, + &CfgAddr, + &AddrSize + ); + + if (EFI_ERROR (Status)) { + if (Status == EFI_INVALID_PARAMETER) { + ShellStatus = SHELL_INVALID_PARAMETER; + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_LACK_ARGUMENTS), gShellNetwork2HiiHandle, L"dns"); + continue; + } else { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + } + // + // Set static DNS server ip6 address list. + // + Status = IfCb->IfCfg->SetData ( + IfCb->IfCfg, + Ip6ConfigDataTypeDnsServer, + AddrSize, + CfgAddr + ); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + } else if (StrCmp (VarArg->Arg, L"id") == 0) { + // + // Parse till the next tag or the end of command line. + // + VarArg = VarArg->Next; + Status = IfConfig6ParseInterfaceId (&VarArg, &InterfaceId); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + // + // Set alternative interface id. + // + Status = IfCb->IfCfg->SetData ( + IfCb->IfCfg, + Ip6ConfigDataTypeAltInterfaceId, + sizeof (EFI_IP6_CONFIG_INTERFACE_ID), + InterfaceId + ); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + } else if (StrCmp (VarArg->Arg, L"dad") == 0) { + // + // Parse till the next tag or the end of command line. + // + VarArg = VarArg->Next; + Status = IfConfig6ParseDadXmits (&VarArg, &DadXmits); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + // + // Set dad transmits count. + // + Status = IfCb->IfCfg->SetData ( + IfCb->IfCfg, + Ip6ConfigDataTypeDupAddrDetectTransmits, + sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS), + &DadXmits + ); + + if (EFI_ERROR(Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + } + } + +ON_EXIT: + + if (CfgManAddr != NULL) { + FreePool (CfgManAddr); + } + + if (CfgAddr != NULL) { + FreePool (CfgAddr); + } + + if (MappedEvt != NULL) { + gBS->CloseEvent (MappedEvt); + } + + if (TimeOutEvt != NULL) { + gBS->CloseEvent (TimeOutEvt); + } + + if (IfInfo != NULL) { + FreePool (IfInfo); + } + + return ShellStatus; + +} + +/** + The IfConfig6 main process. + + @param[in] Private The pointer of IFCONFIG6_PRIVATE_DATA. + + @retval SHELL_SUCCESS IfConfig6 processed successfully. + @retval others The IfConfig6 process failed. + +**/ +SHELL_STATUS +IfConfig6 ( + IN IFCONFIG6_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + + ShellStatus = SHELL_SUCCESS; + + // + // Get configure information of all interfaces. + // + Status = IfConfig6GetInterfaceInfo ( + Private->ImageHandle, + Private->IfName, + &Private->IfList + ); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_NOT_FOUND; + goto ON_EXIT; + } + + switch (Private->OpCode) { + case IfConfig6OpList: + ShellStatus = IfConfig6ShowInterfaceInfo (&Private->IfList); + break; + + case IfConfig6OpClear: + ShellStatus = IfConfig6ClearInterfaceInfo (&Private->IfList, Private->IfName); + break; + + case IfConfig6OpSet: + ShellStatus = IfConfig6SetInterfaceInfo (&Private->IfList, Private->VarArg); + break; + + default: + ShellStatus = SHELL_UNSUPPORTED; + } + +ON_EXIT: + + return ShellStatus; +} + +/** + The IfConfig6 cleanup process, free the allocated memory. + + @param[in] Private The pointer of IFCONFIG6_PRIVATE_DATA. + +**/ +VOID +IfConfig6Cleanup ( + IN IFCONFIG6_PRIVATE_DATA *Private + ) +{ + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + IFCONFIG6_INTERFACE_CB *IfCb; + + ASSERT (Private != NULL); + + // + // Clean the list which save the set config Args. + // + if (Private->VarArg != NULL) { + IfConfig6FreeArgList (Private->VarArg); + } + + if (Private->IfName != NULL) + FreePool (Private->IfName); + + + // + // Clean the IFCONFIG6_INTERFACE_CB list. + // + Entry = Private->IfList.ForwardLink; + NextEntry = Entry->ForwardLink; + + while (Entry != &Private->IfList) { + + IfCb = BASE_CR (Entry, IFCONFIG6_INTERFACE_CB, Link); + + RemoveEntryList (&IfCb->Link); + + if (IfCb->IfId != NULL) { + + FreePool (IfCb->IfId); + } + + if (IfCb->IfInfo != NULL) { + + FreePool (IfCb->IfInfo); + } + + FreePool (IfCb); + + Entry = NextEntry; + NextEntry = Entry->ForwardLink; + } + + FreePool (Private); +} + +/** + Function for 'ifconfig6' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). + + @retval SHELL_SUCCESS ifconfig6 command processed successfully. + @retval others The ifconfig6 command process failed. + +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunIfconfig6 ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + IFCONFIG6_PRIVATE_DATA *Private; + LIST_ENTRY *ParamPackage; + CONST CHAR16 *ValueStr; + ARG_LIST *ArgList; + CHAR16 *ProblemParam; + CHAR16 *Str; + + Private = NULL; + Status = EFI_INVALID_PARAMETER; + ShellStatus = SHELL_SUCCESS; + + Status = ShellCommandLineParseEx (mIfConfig6CheckList, &ParamPackage, &ProblemParam, TRUE, FALSE); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_INVALID_COMMAND), gShellNetwork2HiiHandle, L"ifconfig6", ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + + // + // To handle no option. + // + if (!ShellCommandLineGetFlag (ParamPackage, L"-r") && !ShellCommandLineGetFlag (ParamPackage, L"-s") && + !ShellCommandLineGetFlag (ParamPackage, L"-?") && !ShellCommandLineGetFlag (ParamPackage, L"-l")) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_LACK_OPTION), gShellNetwork2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + // + // To handle conflict options. + // + if (((ShellCommandLineGetFlag (ParamPackage, L"-r")) && (ShellCommandLineGetFlag (ParamPackage, L"-s"))) || + ((ShellCommandLineGetFlag (ParamPackage, L"-r")) && (ShellCommandLineGetFlag (ParamPackage, L"-l"))) || + ((ShellCommandLineGetFlag (ParamPackage, L"-r")) && (ShellCommandLineGetFlag (ParamPackage, L"-?"))) || + ((ShellCommandLineGetFlag (ParamPackage, L"-s")) && (ShellCommandLineGetFlag (ParamPackage, L"-l"))) || + ((ShellCommandLineGetFlag (ParamPackage, L"-s")) && (ShellCommandLineGetFlag (ParamPackage, L"-?"))) || + ((ShellCommandLineGetFlag (ParamPackage, L"-l")) && (ShellCommandLineGetFlag (ParamPackage, L"-?")))) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_CONFLICT_OPTIONS), gShellNetwork2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + + Private = AllocateZeroPool (sizeof (IFCONFIG6_PRIVATE_DATA)); + + if (Private == NULL) { + ShellStatus = SHELL_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + InitializeListHead (&Private->IfList); + + // + // To get interface name for the list option. + // + if (ShellCommandLineGetFlag (ParamPackage, L"-l")) { + Private->OpCode = IfConfig6OpList; + ValueStr = ShellCommandLineGetValue (ParamPackage, L"-l"); + if (ValueStr != NULL) { + Str = AllocateCopyPool (StrSize (ValueStr), ValueStr); + if (Str == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellNetwork2HiiHandle, L"ifconfig6"); + ShellStatus = SHELL_OUT_OF_RESOURCES; + goto ON_EXIT; + } + Private->IfName = Str; + } + } + // + // To get interface name for the clear option. + // + if (ShellCommandLineGetFlag (ParamPackage, L"-r")) { + Private->OpCode = IfConfig6OpClear; + ValueStr = ShellCommandLineGetValue (ParamPackage, L"-r"); + if (ValueStr != NULL) { + Str = AllocateCopyPool (StrSize (ValueStr), ValueStr); + if (Str == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellNetwork2HiiHandle, L"ifconfig6"); + ShellStatus = SHELL_OUT_OF_RESOURCES; + goto ON_EXIT; + } + Private->IfName = Str; + } + } + // + // To get interface name and corresponding Args for the set option. + // + if (ShellCommandLineGetFlag (ParamPackage, L"-s")) { + + ValueStr = ShellCommandLineGetValue (ParamPackage, L"-s"); + if (ValueStr == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_LACK_INTERFACE), gShellNetwork2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + // + // To split the configuration into multi-section. + // + ArgList = IfConfig6SplitStrToList (ValueStr, L' '); + if (ArgList == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellNetwork2HiiHandle, L"ifconfig6"); + ShellStatus = SHELL_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + Private->OpCode = IfConfig6OpSet; + Private->IfName = ArgList->Arg; + + Private->VarArg = ArgList->Next; + + if (Private->IfName == NULL || Private->VarArg == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_LACK_COMMAND), gShellNetwork2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + } + // + // Main process of ifconfig6. + // + ShellStatus = IfConfig6 (Private); + +ON_EXIT: + + ShellCommandLineFreeVarList (ParamPackage); + if (Private != NULL) { + IfConfig6Cleanup (Private); + } + return ShellStatus; + +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork2CommandsLib/Ping6.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork2CommandsLib/Ping6.c new file mode 100644 index 00000000..9a475927 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork2CommandsLib/Ping6.c @@ -0,0 +1,1367 @@ +/** @file + The implementation for Ping6 application. + + Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UefiShellNetwork2CommandsLib.h" + +#define PING6_DEFAULT_TIMEOUT 5000 +#define PING6_MAX_SEND_NUMBER 10000 +#define PING6_MAX_BUFFER_SIZE 32768 +#define PING6_ONE_SECOND 10000000 +#define STALL_1_MILLI_SECOND 1000 + +#pragma pack(1) + +typedef struct _ICMP6_ECHO_REQUEST_REPLY { + UINT8 Type; + UINT8 Code; + UINT16 Checksum; + UINT16 Identifier; + UINT16 SequenceNum; + UINT32 TimeStamp; + UINT8 Data[1]; +} ICMP6_ECHO_REQUEST_REPLY; + +#pragma pack() + +typedef struct _PING6_ICMP6_TX_INFO { + LIST_ENTRY Link; + UINT16 SequenceNum; + UINT32 TimeStamp; + EFI_IP6_COMPLETION_TOKEN *Token; +} PING6_ICMP6_TX_INFO; + +typedef struct _PING6_PRIVATE_DATA { + EFI_HANDLE ImageHandle; + EFI_HANDLE NicHandle; + EFI_HANDLE Ip6ChildHandle; + EFI_IP6_PROTOCOL *Ip6; + EFI_EVENT Timer; + + UINT32 TimerPeriod; + UINT32 RttTimerTick; + EFI_EVENT RttTimer; + + EFI_STATUS Status; + LIST_ENTRY TxList; + EFI_IP6_COMPLETION_TOKEN RxToken; + UINT16 RxCount; + UINT16 TxCount; + UINT64 RttSum; + UINT64 RttMin; + UINT64 RttMax; + UINT32 SequenceNum; + + EFI_IPv6_ADDRESS SrcAddress; + EFI_IPv6_ADDRESS DstAddress; + UINT32 SendNum; + UINT32 BufferSize; +} PING6_PRIVATE_DATA; + + +SHELL_PARAM_ITEM Ping6ParamList[] = { + { + L"-l", + TypeValue + }, + { + L"-n", + TypeValue + }, + { + L"-s", + TypeValue + }, + { + L"-?", + TypeFlag + }, + { + NULL, + TypeMax + }, +}; + +// +// Global Variables in Ping6 application. +// +CONST CHAR16 *mIp6DstString; +CONST CHAR16 *mIp6SrcString; +EFI_CPU_ARCH_PROTOCOL *Cpu = NULL; + +/** + RTT timer tick routine. + + @param[in] Event A EFI_EVENT type event. + @param[in] Context The pointer to Context. + +**/ +VOID +EFIAPI +Ping6RttTimerTickRoutine ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UINT32 *RttTimerTick; + + RttTimerTick = (UINT32*) Context; + (*RttTimerTick)++; +} + +/** + Get the timer period of the system. + + This function tries to get the system timer period by creating + an 1ms period timer. + + @return System timer period in MS, or 0 if operation failed. + +**/ +UINT32 +Ping6GetTimerPeriod( + VOID + ) +{ + EFI_STATUS Status; + UINT32 RttTimerTick; + EFI_EVENT TimerEvent; + UINT32 StallCounter; + EFI_TPL OldTpl; + + RttTimerTick = 0; + StallCounter = 0; + + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + Ping6RttTimerTickRoutine, + &RttTimerTick, + &TimerEvent + ); + if (EFI_ERROR (Status)) { + return 0; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + Status = gBS->SetTimer ( + TimerEvent, + TimerPeriodic, + TICKS_PER_MS + ); + if (EFI_ERROR (Status)) { + gBS->CloseEvent (TimerEvent); + return 0; + } + + while (RttTimerTick < 10) { + gBS->Stall (STALL_1_MILLI_SECOND); + ++StallCounter; + } + + gBS->RestoreTPL (OldTpl); + + gBS->SetTimer (TimerEvent, TimerCancel, 0); + gBS->CloseEvent (TimerEvent); + + return StallCounter / RttTimerTick; +} + + +/** + Initialize the timer event for RTT (round trip time). + + @param[in] Private The pointer to PING6_PRIVATE_DATA. + + @retval EFI_SUCCESS RTT timer is started. + @retval Others Failed to start the RTT timer. + +**/ +EFI_STATUS +Ping6InitRttTimer ( + IN PING6_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + + Private->TimerPeriod = Ping6GetTimerPeriod (); + if (Private->TimerPeriod == 0) { + return EFI_ABORTED; + } + + Private->RttTimerTick = 0; + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + Ping6RttTimerTickRoutine, + &Private->RttTimerTick, + &Private->RttTimer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->SetTimer ( + Private->RttTimer, + TimerPeriodic, + TICKS_PER_MS + ); + if (EFI_ERROR (Status)) { + gBS->CloseEvent (Private->RttTimer); + return Status; + } + + return EFI_SUCCESS; + +} + +/** + Free RTT timer event resource. + + @param[in] Private The pointer to PING6_PRIVATE_DATA. + +**/ +VOID +Ping6FreeRttTimer ( + IN PING6_PRIVATE_DATA *Private + ) +{ + if (Private->RttTimer != NULL) { + gBS->SetTimer (Private->RttTimer, TimerCancel, 0); + gBS->CloseEvent (Private->RttTimer); + } +} + +/** + Read the current time. + + @param[in] Private The pointer to PING6_PRIVATE_DATA. + + @retval the current tick value. +**/ +UINT32 +Ping6ReadTime ( + IN PING6_PRIVATE_DATA *Private + ) +{ + return Private->RttTimerTick; +} + +/** + Get and calculate the duration in ms. + + @param[in] Private The pointer to PING6_PRIVATE_DATA. + @param[in] Begin The start point of time. + @param[in] End The end point of time. + + @return The duration in ms. + +**/ +UINT32 +Ping6CalculateTick ( + IN PING6_PRIVATE_DATA *Private, + IN UINT32 Begin, + IN UINT32 End + ) +{ + if (End < Begin) { + return (0); + } + + return (End - Begin) * Private->TimerPeriod; + +} + +/** + Destroy IPING6_ICMP6_TX_INFO, and recollect the memory. + + @param[in] TxInfo The pointer to PING6_ICMP6_TX_INFO. + +**/ +VOID +Ping6DestroyTxInfo ( + IN PING6_ICMP6_TX_INFO *TxInfo + ) +{ + EFI_IP6_TRANSMIT_DATA *TxData; + EFI_IP6_FRAGMENT_DATA *FragData; + UINTN Index; + + ASSERT (TxInfo != NULL); + + if (TxInfo->Token != NULL) { + + if (TxInfo->Token->Event != NULL) { + gBS->CloseEvent (TxInfo->Token->Event); + } + + TxData = TxInfo->Token->Packet.TxData; + if (TxData != NULL) { + + if (TxData->OverrideData != NULL) { + FreePool (TxData->OverrideData); + } + + if (TxData->ExtHdrs != NULL) { + FreePool (TxData->ExtHdrs); + } + + for (Index = 0; Index < TxData->FragmentCount; Index++) { + FragData = TxData->FragmentTable[Index].FragmentBuffer; + if (FragData != NULL) { + FreePool (FragData); + } + } + } + + FreePool (TxInfo->Token); + } + + FreePool (TxInfo); +} + +/** + Match the request, and reply with SequenceNum/TimeStamp. + + @param[in] Private The pointer to PING6_PRIVATE_DATA. + @param[in] Packet The pointer to ICMP6_ECHO_REQUEST_REPLY. + + @retval EFI_SUCCESS The match is successful. + @retval EFI_NOT_FOUND The reply can't be matched with any request. + +**/ +EFI_STATUS +Ping6OnMatchEchoReply ( + IN PING6_PRIVATE_DATA *Private, + IN ICMP6_ECHO_REQUEST_REPLY *Packet + ) +{ + PING6_ICMP6_TX_INFO *TxInfo; + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + + NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) { + TxInfo = BASE_CR (Entry, PING6_ICMP6_TX_INFO, Link); + + if ((TxInfo->SequenceNum == Packet->SequenceNum) && (TxInfo->TimeStamp == Packet->TimeStamp)) { + Private->RxCount++; + RemoveEntryList (&TxInfo->Link); + Ping6DestroyTxInfo (TxInfo); + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** + The original intention is to send a request. + Currently, the application retransmits an icmp6 echo request packet + per second in sendnumber times that is specified by the user. + Because nothing can be done here, all things move to the timer rountine. + + @param[in] Event A EFI_EVENT type event. + @param[in] Context The pointer to Context. + +**/ +VOID +EFIAPI +Ping6OnEchoRequestSent6 ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ +} + +/** + receive reply, match and print reply infomation. + + @param[in] Event A EFI_EVENT type event. + @param[in] Context The pointer to context. + +**/ +VOID +EFIAPI +Ping6OnEchoReplyReceived6 ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + PING6_PRIVATE_DATA *Private; + EFI_IP6_COMPLETION_TOKEN *RxToken; + EFI_IP6_RECEIVE_DATA *RxData; + ICMP6_ECHO_REQUEST_REPLY *Reply; + UINT32 PayLoad; + UINT32 Rtt; + + Private = (PING6_PRIVATE_DATA *) Context; + + if (Private->Status == EFI_ABORTED) { + return; + } + + RxToken = &Private->RxToken; + RxData = RxToken->Packet.RxData; + Reply = RxData->FragmentTable[0].FragmentBuffer; + PayLoad = RxData->DataLength; + + if (RxData->Header->NextHeader != IP6_ICMP) { + goto ON_EXIT; + } + + if (!IP6_IS_MULTICAST (&Private->DstAddress) && + !EFI_IP6_EQUAL (&RxData->Header->SourceAddress, &Private->DstAddress)) { + goto ON_EXIT; + } + + if ((Reply->Type != ICMP_V6_ECHO_REPLY) || (Reply->Code != 0)) { + goto ON_EXIT; + } + + if (PayLoad != Private->BufferSize) { + goto ON_EXIT; + } + // + // Check whether the reply matches the sent request before. + // + Status = Ping6OnMatchEchoReply (Private, Reply); + if (EFI_ERROR(Status)) { + goto ON_EXIT; + } + // + // Display statistics on this icmp6 echo reply packet. + // + Rtt = Ping6CalculateTick (Private, Reply->TimeStamp, Ping6ReadTime (Private)); + + Private->RttSum += Rtt; + Private->RttMin = Private->RttMin > Rtt ? Rtt : Private->RttMin; + Private->RttMax = Private->RttMax < Rtt ? Rtt : Private->RttMax; + + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_PING6_REPLY_INFO), + gShellNetwork2HiiHandle, + PayLoad, + mIp6DstString, + Reply->SequenceNum, + RxData->Header->HopLimit, + Rtt, + Rtt + Private->TimerPeriod + ); + +ON_EXIT: + + if (Private->RxCount < Private->SendNum) { + // + // Continue to receive icmp6 echo reply packets. + // + RxToken->Status = EFI_ABORTED; + + Status = Private->Ip6->Receive (Private->Ip6, RxToken); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6_RECEIVE), gShellNetwork2HiiHandle, Status); + Private->Status = EFI_ABORTED; + } + } else { + // + // All reply have already been received from the dest host. + // + Private->Status = EFI_SUCCESS; + } + // + // Singal to recycle the each rxdata here, not at the end of process. + // + gBS->SignalEvent (RxData->RecycleSignal); +} + +/** + Initial EFI_IP6_COMPLETION_TOKEN. + + @param[in] Private The pointer of PING6_PRIVATE_DATA. + @param[in] TimeStamp The TimeStamp of request. + @param[in] SequenceNum The SequenceNum of request. + + @return The pointer of EFI_IP6_COMPLETION_TOKEN. + +**/ +EFI_IP6_COMPLETION_TOKEN * +Ping6GenerateToken ( + IN PING6_PRIVATE_DATA *Private, + IN UINT32 TimeStamp, + IN UINT16 SequenceNum + ) +{ + EFI_STATUS Status; + EFI_IP6_COMPLETION_TOKEN *Token; + EFI_IP6_TRANSMIT_DATA *TxData; + ICMP6_ECHO_REQUEST_REPLY *Request; + + Request = AllocateZeroPool (Private->BufferSize); + + if (Request == NULL) { + return NULL; + } + // + // Assembly icmp6 echo request packet. + // + Request->Type = ICMP_V6_ECHO_REQUEST; + Request->Code = 0; + Request->SequenceNum = SequenceNum; + Request->TimeStamp = TimeStamp; + Request->Identifier = 0; + // + // Leave check sum to ip6 layer, since it has no idea of source address + // selection. + // + Request->Checksum = 0; + + TxData = AllocateZeroPool (sizeof (EFI_IP6_TRANSMIT_DATA)); + + if (TxData == NULL) { + FreePool (Request); + return NULL; + } + // + // Assembly ipv6 token for transmit. + // + TxData->OverrideData = 0; + TxData->ExtHdrsLength = 0; + TxData->ExtHdrs = NULL; + TxData->DataLength = Private->BufferSize; + TxData->FragmentCount = 1; + TxData->FragmentTable[0].FragmentBuffer = (VOID *) Request; + TxData->FragmentTable[0].FragmentLength = Private->BufferSize; + + Token = AllocateZeroPool (sizeof (EFI_IP6_COMPLETION_TOKEN)); + + if (Token == NULL) { + FreePool (Request); + FreePool (TxData); + return NULL; + } + + Token->Status = EFI_ABORTED; + Token->Packet.TxData = TxData; + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + Ping6OnEchoRequestSent6, + Private, + &Token->Event + ); + + if (EFI_ERROR (Status)) { + FreePool (Request); + FreePool (TxData); + FreePool (Token); + return NULL; + } + + return Token; +} + +/** + Transmit the EFI_IP6_COMPLETION_TOKEN. + + @param[in] Private The pointer of PING6_PRIVATE_DATA. + + @retval EFI_SUCCESS Transmitted successfully. + @retval EFI_OUT_OF_RESOURCES No memory is available on the platform. + @retval others Transmitted unsuccessfully. + +**/ +EFI_STATUS +Ping6SendEchoRequest ( + IN PING6_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + PING6_ICMP6_TX_INFO *TxInfo; + + TxInfo = AllocateZeroPool (sizeof (PING6_ICMP6_TX_INFO)); + + if (TxInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + TxInfo->TimeStamp = Ping6ReadTime (Private); + TxInfo->SequenceNum = (UINT16) (Private->TxCount + 1); + + TxInfo->Token = Ping6GenerateToken ( + Private, + TxInfo->TimeStamp, + TxInfo->SequenceNum + ); + + if (TxInfo->Token == NULL) { + Ping6DestroyTxInfo (TxInfo); + return EFI_OUT_OF_RESOURCES; + } + + Status = Private->Ip6->Transmit (Private->Ip6, TxInfo->Token); + + if (EFI_ERROR (Status)) { + Ping6DestroyTxInfo (TxInfo); + return Status; + } + + InsertTailList (&Private->TxList, &TxInfo->Link); + Private->TxCount++; + + return EFI_SUCCESS; +} + +/** + Place a completion token into the receive packet queue to receive the echo reply. + + @param[in] Private The pointer of PING6_PRIVATE_DATA. + + @retval EFI_SUCCESS Put the token into the receive packet queue successfully. + @retval others Put the token into the receive packet queue unsuccessfully. + +**/ +EFI_STATUS +Ping6OnReceiveEchoReply ( + IN PING6_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + + ZeroMem (&Private->RxToken, sizeof (EFI_IP6_COMPLETION_TOKEN)); + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + Ping6OnEchoReplyReceived6, + Private, + &Private->RxToken.Event + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Private->RxToken.Status = EFI_NOT_READY; + + Status = Private->Ip6->Receive (Private->Ip6, &Private->RxToken); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6_RECEIVE), gShellNetwork2HiiHandle, Status); + } + return Status; +} + +/** + Remove the timeout request from the list. + + @param[in] Event A EFI_EVENT type event. + @param[in] Context The pointer to Context. + +**/ +VOID +EFIAPI +Ping6OnTimerRoutine6 ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + PING6_PRIVATE_DATA *Private; + PING6_ICMP6_TX_INFO *TxInfo; + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + UINT64 Time; + + Private = (PING6_PRIVATE_DATA *) Context; + + // + // Retransmit icmp6 echo request packets per second in sendnumber times. + // + if (Private->TxCount < Private->SendNum) { + + Status = Ping6SendEchoRequest (Private); + if (Private->TxCount != 0){ + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_SEND_REQUEST), gShellNetwork2HiiHandle, Private->TxCount + 1); + } + } + } + // + // Check whether any icmp6 echo request in the list timeout. + // + NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) { + TxInfo = BASE_CR (Entry, PING6_ICMP6_TX_INFO, Link); + Time = Ping6CalculateTick (Private, TxInfo->TimeStamp, Ping6ReadTime (Private)); + + // + // Remove the timeout echo request from txlist. + // + if (Time > PING6_DEFAULT_TIMEOUT) { + + if (EFI_ERROR (TxInfo->Token->Status)) { + Private->Ip6->Cancel (Private->Ip6, TxInfo->Token); + } + // + // Remove the timeout icmp6 echo request from list. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_TIMEOUT), gShellNetwork2HiiHandle, TxInfo->SequenceNum); + + RemoveEntryList (&TxInfo->Link); + Ping6DestroyTxInfo (TxInfo); + + if (IsListEmpty (&Private->TxList) && (Private->TxCount == Private->SendNum)) { + // + // All the left icmp6 echo request in the list timeout. + // + Private->Status = EFI_TIMEOUT; + } + } + } +} + +/** + Create a valid IP6 instance. + + @param[in] Private The pointer of PING6_PRIVATE_DATA. + + @retval EFI_SUCCESS Create a valid IP6 instance successfully. + @retval EFI_ABORTED Locate handle with ip6 service binding protocol unsuccessfully. + @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link -ocal address. + @retval EFI_OUT_OF_RESOURCES No memory is available on the platform. + @retval EFI_NOT_FOUND The source address is not found. +**/ +EFI_STATUS +Ping6CreateIpInstance ( + IN PING6_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + UINTN HandleIndex; + UINTN HandleNum; + EFI_HANDLE *HandleBuffer; + BOOLEAN UnspecifiedSrc; + EFI_STATUS MediaStatus; + EFI_SERVICE_BINDING_PROTOCOL *Ip6Sb; + EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg; + EFI_IP6_CONFIG_DATA Ip6Config; + EFI_IP6_CONFIG_INTERFACE_INFO *IfInfo; + UINTN IfInfoSize; + EFI_IPv6_ADDRESS *Addr; + UINTN AddrIndex; + + HandleBuffer = NULL; + UnspecifiedSrc = FALSE; + MediaStatus = EFI_SUCCESS; + Ip6Sb = NULL; + IfInfo = NULL; + IfInfoSize = 0; + + // + // Locate all the handles with ip6 service binding protocol. + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiIp6ServiceBindingProtocolGuid, + NULL, + &HandleNum, + &HandleBuffer + ); + if (EFI_ERROR (Status) || (HandleNum == 0)) { + return EFI_ABORTED; + } + + if (NetIp6IsUnspecifiedAddr (&Private->SrcAddress)) { + // + // SrcAddress is unspecified. So, both connected and configured interface will be automatic selected. + // + UnspecifiedSrc = TRUE; + } + + // + // Source address is required when pinging a link-local address. + // + if (NetIp6IsLinkLocalAddr (&Private->DstAddress) && UnspecifiedSrc) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_SOURCE), gShellNetwork2HiiHandle); + Status = EFI_INVALID_PARAMETER; + goto ON_ERROR; + } + + // + // For each ip6 protocol, check interface addresses list. + // + for (HandleIndex = 0; HandleIndex < HandleNum; HandleIndex++) { + + Ip6Sb = NULL; + IfInfo = NULL; + IfInfoSize = 0; + + if (UnspecifiedSrc) { + // + // Check media. + // + NetLibDetectMediaWaitTimeout (HandleBuffer[HandleIndex], 0, &MediaStatus); + if (MediaStatus != EFI_SUCCESS) { + // + // Skip this one. + // + continue; + } + } + + Status = gBS->HandleProtocol ( + HandleBuffer[HandleIndex], + &gEfiIp6ServiceBindingProtocolGuid, + (VOID **) &Ip6Sb + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Ip6config protocol and ip6 service binding protocol are installed + // on the same handle. + // + Status = gBS->HandleProtocol ( + HandleBuffer[HandleIndex], + &gEfiIp6ConfigProtocolGuid, + (VOID **) &Ip6Cfg + ); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + // + // Get the interface information size. + // + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeInterfaceInfo, + &IfInfoSize, + NULL + ); + + if (Status != EFI_BUFFER_TOO_SMALL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status); + goto ON_ERROR; + } + + IfInfo = AllocateZeroPool (IfInfoSize); + + if (IfInfo == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + // + // Get the interface info. + // + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeInterfaceInfo, + &IfInfoSize, + IfInfo + ); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status); + goto ON_ERROR; + } + // + // Check whether the source address is one of the interface addresses. + // + for (AddrIndex = 0; AddrIndex < IfInfo->AddressInfoCount; AddrIndex++) { + Addr = &(IfInfo->AddressInfo[AddrIndex].Address); + + if (UnspecifiedSrc) { + if (!NetIp6IsUnspecifiedAddr (Addr) && !NetIp6IsLinkLocalAddr (Addr)) { + // + // Select the interface automatically. + // + CopyMem(&Private->SrcAddress, Addr, sizeof(Private->SrcAddress)); + break; + } + } else if (EFI_IP6_EQUAL (&Private->SrcAddress, Addr)) { + // + // Match a certain interface address. + // + break; + } + } + + if (AddrIndex < IfInfo->AddressInfoCount) { + // + // Found a nic handle with right interface address. + // + break; + } + + FreePool (IfInfo); + IfInfo = NULL; + } + // + // No exact interface address matched. + // + + if (HandleIndex == HandleNum) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_CONFIGD_NIC_NF), gShellNetwork2HiiHandle); + Status = EFI_NOT_FOUND; + goto ON_ERROR; + } + + Private->NicHandle = HandleBuffer[HandleIndex]; + + ASSERT (Ip6Sb != NULL); + Status = Ip6Sb->CreateChild (Ip6Sb, &Private->Ip6ChildHandle); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Status = gBS->OpenProtocol ( + Private->Ip6ChildHandle, + &gEfiIp6ProtocolGuid, + (VOID **) &Private->Ip6, + Private->ImageHandle, + Private->Ip6ChildHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + ZeroMem (&Ip6Config, sizeof (EFI_IP6_CONFIG_DATA)); + + // + // Configure the ip6 instance for icmp6 packet exchange. + // + Ip6Config.DefaultProtocol = 58; + Ip6Config.AcceptAnyProtocol = FALSE; + Ip6Config.AcceptIcmpErrors = TRUE; + Ip6Config.AcceptPromiscuous = FALSE; + Ip6Config.TrafficClass = 0; + Ip6Config.HopLimit = 128; + Ip6Config.FlowLabel = 0; + Ip6Config.ReceiveTimeout = 0; + Ip6Config.TransmitTimeout = 0; + + IP6_COPY_ADDRESS (&Ip6Config.StationAddress, &Private->SrcAddress); + + IP6_COPY_ADDRESS (&Ip6Config.DestinationAddress, &Private->DstAddress); + + Status = Private->Ip6->Configure (Private->Ip6, &Ip6Config); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6_CONFIG), gShellNetwork2HiiHandle, Status); + goto ON_ERROR; + } + + return EFI_SUCCESS; + +ON_ERROR: + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + + if (IfInfo != NULL) { + FreePool (IfInfo); + } + + if ((Ip6Sb != NULL) && (Private->Ip6ChildHandle != NULL)) { + Ip6Sb->DestroyChild (Ip6Sb, Private->Ip6ChildHandle); + } + + return Status; +} + +/** + Destroy the IP6 instance. + + @param[in] Private The pointer of PING6_PRIVATE_DATA. + +**/ +VOID +Ping6DestroyIpInstance ( + IN PING6_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + EFI_SERVICE_BINDING_PROTOCOL *Ip6Sb; + + gBS->CloseProtocol ( + Private->Ip6ChildHandle, + &gEfiIp6ProtocolGuid, + Private->ImageHandle, + Private->Ip6ChildHandle + ); + + Status = gBS->HandleProtocol ( + Private->NicHandle, + &gEfiIp6ServiceBindingProtocolGuid, + (VOID **) &Ip6Sb + ); + + if (!EFI_ERROR(Status)) { + Ip6Sb->DestroyChild (Ip6Sb, Private->Ip6ChildHandle); + } +} + +/** + The Ping6 Process. + + @param[in] ImageHandle The firmware allocated handle for the UEFI image. + @param[in] SendNumber The send request count. + @param[in] BufferSize The send buffer size. + @param[in] SrcAddress The source IPv6 address. + @param[in] DstAddress The destination IPv6 address. + + @retval SHELL_SUCCESS The ping6 processed successfullly. + @retval others The ping6 processed unsuccessfully. + +**/ +SHELL_STATUS +ShellPing6 ( + IN EFI_HANDLE ImageHandle, + IN UINT32 SendNumber, + IN UINT32 BufferSize, + IN EFI_IPv6_ADDRESS *SrcAddress, + IN EFI_IPv6_ADDRESS *DstAddress + ) +{ + EFI_STATUS Status; + EFI_INPUT_KEY Key; + PING6_PRIVATE_DATA *Private; + PING6_ICMP6_TX_INFO *TxInfo; + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + SHELL_STATUS ShellStatus; + + ShellStatus = SHELL_SUCCESS; + Private = AllocateZeroPool (sizeof (PING6_PRIVATE_DATA)); + + if (Private == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellNetwork2HiiHandle, L"Ping6"); + ShellStatus = SHELL_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + Private->ImageHandle = ImageHandle; + Private->SendNum = SendNumber; + Private->BufferSize = BufferSize; + Private->RttMin = ~((UINT64 )(0x0)); + Private->Status = EFI_NOT_READY; + + InitializeListHead (&Private->TxList); + + IP6_COPY_ADDRESS (&Private->SrcAddress, SrcAddress); + IP6_COPY_ADDRESS (&Private->DstAddress, DstAddress); + + // + // Open and configure a ip6 instance for ping6. + // + Status = Ping6CreateIpInstance (Private); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + // + // Print the command line itself. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_START), gShellNetwork2HiiHandle, mIp6DstString, Private->BufferSize); + // + // Create a ipv6 token to receive the first icmp6 echo reply packet. + // + Status = Ping6OnReceiveEchoReply (Private); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + // + // Create and start timer to send icmp6 echo request packet per second. + // + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + Ping6OnTimerRoutine6, + Private, + &Private->Timer + ); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + // + // Start a timer to calculate the RTT. + // + Status = Ping6InitRttTimer (Private); + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + // + // Create a ipv6 token to send the first icmp6 echo request packet. + // + Status = Ping6SendEchoRequest (Private); + // + // EFI_NOT_READY for IPsec is enable and IKE is not established. + // + if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) { + ShellStatus = SHELL_ACCESS_DENIED; + if(Status == EFI_NOT_FOUND) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_NOSOURCE_INDOMAIN), gShellNetwork2HiiHandle, mIp6DstString); + } + + goto ON_EXIT; + } + + Status = gBS->SetTimer ( + Private->Timer, + TimerPeriodic, + PING6_ONE_SECOND + ); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + // + // Control the ping6 process by two factors: + // 1. Hot key + // 2. Private->Status + // 2.1. success means all icmp6 echo request packets get reply packets. + // 2.2. timeout means the last icmp6 echo reply request timeout to get reply. + // 2.3. noready means ping6 process is on-the-go. + // + while (Private->Status == EFI_NOT_READY) { + Private->Ip6->Poll (Private->Ip6); + + // + // Terminate the ping6 process by 'esc' or 'ctl-c'. + // + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + + if (!EFI_ERROR(Status)) { + if ((Key.UnicodeChar == 0x1b) || (Key.UnicodeChar == 0x03) || + ((Key.UnicodeChar == 0) && (Key.ScanCode == SCAN_ESC))) { + goto ON_STAT; + } + } + } + +ON_STAT: + // + // Display the statistics in all. + // + gBS->SetTimer (Private->Timer, TimerCancel, 0); + + if (Private->TxCount != 0) { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_PING6_STAT), + gShellNetwork2HiiHandle, + Private->TxCount, + Private->RxCount, + (100 * (Private->TxCount - Private->RxCount)) / Private->TxCount, + Private->RttSum + ); + } + + if (Private->RxCount != 0) { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_PING6_RTT), + gShellNetwork2HiiHandle, + Private->RttMin, + Private->RttMin + Private->TimerPeriod, + Private->RttMax, + Private->RttMax + Private->TimerPeriod, + DivU64x64Remainder (Private->RttSum, Private->RxCount, NULL), + DivU64x64Remainder (Private->RttSum, Private->RxCount, NULL) + Private->TimerPeriod + ); + } + +ON_EXIT: + + if (Private != NULL) { + Private->Status = EFI_ABORTED; + + NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) { + TxInfo = BASE_CR (Entry, PING6_ICMP6_TX_INFO, Link); + + Status = Private->Ip6->Cancel (Private->Ip6, TxInfo->Token); + + RemoveEntryList (&TxInfo->Link); + Ping6DestroyTxInfo (TxInfo); + } + + Ping6FreeRttTimer (Private); + + if (Private->Timer != NULL) { + gBS->CloseEvent (Private->Timer); + } + + if (Private->Ip6 != NULL) { + Status = Private->Ip6->Cancel (Private->Ip6, &Private->RxToken); + } + + if (Private->RxToken.Event != NULL) { + gBS->CloseEvent (Private->RxToken.Event); + } + + if (Private->Ip6ChildHandle != NULL) { + Ping6DestroyIpInstance (Private); + } + + FreePool (Private); + } + + return ShellStatus; +} + +/** + Function for 'ping6' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). + + @retval SHELL_SUCCESS The ping6 processed successfullly. + @retval others The ping6 processed unsuccessfully. + +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunPing6 ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + EFI_IPv6_ADDRESS DstAddress; + EFI_IPv6_ADDRESS SrcAddress; + UINT64 BufferSize; + UINTN SendNumber; + LIST_ENTRY *ParamPackage; + CONST CHAR16 *ValueStr; + CONST CHAR16 *ValueStrPtr; + UINTN NonOptionCount; + CHAR16 *ProblemParam; + + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + + Status = ShellCommandLineParseEx (Ping6ParamList, &ParamPackage, &ProblemParam, TRUE, FALSE); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_INPUT), gShellNetwork2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + + SendNumber = 10; + BufferSize = 16; + + // + // Parse the parameter of count number. + // + ValueStr = ShellCommandLineGetValue (ParamPackage, L"-n"); + ValueStrPtr = ValueStr; + if (ValueStr != NULL) { + SendNumber = ShellStrToUintn (ValueStrPtr); + + // + // ShellStrToUintn will return 0 when input is 0 or an invalid input string. + // + if ((SendNumber == 0) || (SendNumber > PING6_MAX_SEND_NUMBER)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_SEND_NUMBER), gShellNetwork2HiiHandle, ValueStr); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + } + // + // Parse the parameter of buffer size. + // + ValueStr = ShellCommandLineGetValue (ParamPackage, L"-l"); + ValueStrPtr = ValueStr; + if (ValueStr != NULL) { + BufferSize = ShellStrToUintn (ValueStrPtr); + + // + // ShellStrToUintn will return 0 when input is 0 or an invalid input string. + // + if ((BufferSize < 16) || (BufferSize > PING6_MAX_BUFFER_SIZE)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_BUFFER_SIZE), gShellNetwork2HiiHandle, ValueStr); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + } + + ZeroMem (&SrcAddress, sizeof (EFI_IPv6_ADDRESS)); + ZeroMem (&DstAddress, sizeof (EFI_IPv6_ADDRESS)); + + // + // Parse the parameter of source ip address. + // + ValueStr = ShellCommandLineGetValue (ParamPackage, L"-s"); + ValueStrPtr = ValueStr; + if (ValueStr != NULL) { + mIp6SrcString = ValueStr; + Status = NetLibStrToIp6 (ValueStrPtr, &SrcAddress); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_IP), gShellNetwork2HiiHandle, ValueStr); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + } + // + // Parse the parameter of destination ip address. + // + NonOptionCount = ShellCommandLineGetCount(ParamPackage); + ValueStr = ShellCommandLineGetRawValue (ParamPackage, (UINT32)(NonOptionCount-1)); + if (NonOptionCount != 2) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_INPUT), gShellNetwork2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + ValueStrPtr = ValueStr; + if (ValueStr != NULL) { + mIp6DstString = ValueStr; + Status = NetLibStrToIp6 (ValueStrPtr, &DstAddress); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_IP), gShellNetwork2HiiHandle, ValueStr); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + } + + // + // Enter into ping6 process. + // + ShellStatus = ShellPing6 ( + ImageHandle, + (UINT32)SendNumber, + (UINT32)BufferSize, + &SrcAddress, + &DstAddress + ); + +ON_EXIT: + ShellCommandLineFreeVarList (ParamPackage); + return ShellStatus; +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.c new file mode 100644 index 00000000..65c76fc2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.c @@ -0,0 +1,86 @@ +/** @file + Main file for NULL named library for network2 shell command functions. + + Copyright (c) 2016, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "UefiShellNetwork2CommandsLib.h" + +CONST CHAR16 gShellNetwork2FileName[] = L"ShellCommands"; +EFI_HII_HANDLE gShellNetwork2HiiHandle = NULL; + +/** + return the file name of the help text file if not using HII. + + @return The string pointer to the file name. +**/ +CONST CHAR16* +EFIAPI +ShellCommandGetManFileNameNetwork2 ( + VOID + ) +{ + return (gShellNetwork2FileName); +} + +/** + Constructor for the Shell Network2 Commands library. + + Install the handlers for Network2 UEFI Shell 2.0 profile commands. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. + + @retval EFI_SUCCESS The shell command handlers were installed sucessfully. + @retval EFI_UNSUPPORTED The shell level required was not found. +**/ +EFI_STATUS +EFIAPI +ShellNetwork2CommandsLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + gShellNetwork2HiiHandle = NULL; + + // + // check our bit of the profiles mask + // + if ((PcdGet8(PcdShellProfileMask) & BIT4) == 0) { + return (EFI_SUCCESS); + } + + gShellNetwork2HiiHandle = HiiAddPackages (&gShellNetwork2HiiGuid, gImageHandle, UefiShellNetwork2CommandsLibStrings, NULL); + if (gShellNetwork2HiiHandle == NULL) { + return (EFI_DEVICE_ERROR); + } + // + // install our shell command handlers + // + ShellCommandRegisterCommandName(L"ping6", ShellCommandRunPing6 , ShellCommandGetManFileNameNetwork2, 0, L"network2", TRUE , gShellNetwork2HiiHandle, STRING_TOKEN(STR_GET_HELP_PING6)); + ShellCommandRegisterCommandName(L"ifconfig6",ShellCommandRunIfconfig6 , ShellCommandGetManFileNameNetwork2, 0, L"network2", TRUE , gShellNetwork2HiiHandle, STRING_TOKEN(STR_GET_HELP_IFCONFIG6)); + + return EFI_SUCCESS; + +} + +/** + Destructor for the library. free any resources. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. +**/ +EFI_STATUS +EFIAPI +ShellNetwork2CommandsLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + if (gShellNetwork2HiiHandle != NULL) { + HiiRemovePackages(gShellNetwork2HiiHandle); + } + return EFI_SUCCESS; +} + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.h new file mode 100644 index 00000000..59c4b241 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.h @@ -0,0 +1,67 @@ +/** @file + Main file for NULL named library for network2 shell command functions. + + Copyright (c) 2016, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _UEFI_SHELL_NETWORK2_COMMANDS_LIB_H_ +#define _UEFI_SHELL_NETWORK2_COMMANDS_LIB_H_ + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern EFI_HII_HANDLE gShellNetwork2HiiHandle; + +/** + Function for 'ping6' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). + + @retval SHELL_SUCCESS The ping6 processed successfullly. + @retval others The ping6 processed unsuccessfully. + +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunPing6 ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'ifconfig6' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). + + @retval SHELL_SUCCESS The ifconfig6 command processed successfully. + @retval others The ifconfig6 command process failed. + +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunIfconfig6 ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +#endif + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.inf new file mode 100644 index 00000000..7b984d51 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.inf @@ -0,0 +1,60 @@ +## @file +# Provides shell network2 functions +# +# Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiShellNetwork2CommandsLib + FILE_GUID = D94E3B82-908E-46bf-A7B9-C7B7F17B1B7D + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = ShellNetwork2CommandsLibConstructor + DESTRUCTOR = ShellNetwork2CommandsLibDestructor + +[Sources.common] + UefiShellNetwork2CommandsLib.uni + UefiShellNetwork2CommandsLib.c + UefiShellNetwork2CommandsLib.h + Ping6.c + Ifconfig6.c + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + NetworkPkg/NetworkPkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + ShellCommandLib + ShellLib + UefiLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + PcdLib + HiiLib + FileHandleLib + NetLib + +[Pcd] + gEfiShellPkgTokenSpaceGuid.PcdShellProfileMask ## CONSUMES + +[Protocols] + gEfiCpuArchProtocolGuid ## CONSUMES + gEfiTimerArchProtocolGuid ## CONSUMES + gEfiIp6ProtocolGuid ## SOMETIMES_CONSUMES + gEfiIp6ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES + gEfiIp6ConfigProtocolGuid ## SOMETIMES_CONSUMES + +[Guids] + gShellNetwork2HiiGuid ## SOMETIMES_CONSUMES ## HII diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.uni b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.uni new file mode 100644 index 00000000..30913ae5 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.uni @@ -0,0 +1,160 @@ +/** @file + + String definitions for UEFI Shell network 2 commands + Copyright (c) 2016, Intel Corporation. All rights reserved.
+ (C) Copyright 2017 Hewlett Packard Enterprise Development LP
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + + Module Name: + + UefiShellNetwork2CommandsLib.uni + + Abstract: + + String definitions for UEFI Shell 2.0 network 2 commands +**/ + +#langdef en-US "english" + +#string STR_GEN_ERR_AD #language en-US "%H%s%N: Access denied.\r\n" +#string STR_GEN_OUT_MEM #language en-US "%H%s%N: Memory allocation was not successful.\r\n" + +#string STR_PING6_INVALID_IP #language en-US "%Ping6: Invalid IP6 address, %s\r\n" +#string STR_PING6_INVALID_INPUT #language en-US "%Ping6: Invalid input, please type 'Ping6 -?'for help\r\n" +#string STR_PING6_INVALID_SEND_NUMBER #language en-US "%Ping6: Invalid send number, %s\r\n" +#string STR_PING6_INVALID_BUFFER_SIZE #language en-US "%Ping6: Invalid buffer size, %s\r\n" +#string STR_PING6_INVALID_SOURCE #language en-US "%Ping6: Require source interface option\r\n" +#string STR_PING6_IP6_CONFIG #language en-US "%Ping6: The process of Ip6 Configure %r\r\n" +#string STR_PING6_IP6_RECEIVE #language en-US "%Ping6: Place the receive token %r\r\n" +#string STR_PING6_IP6CFG_GETDATA #language en-US "%Ping6: Get data of the interface information %r\r\n" +#string STR_PING6_SEND_REQUEST #language en-US "Echo request sequence %d fails.\r\n" +#string STR_PING6_CONFIGD_NIC_NF #language en-US "%Ping6: No configured interfaces were found.\r\n" +#string STR_PING6_NOSOURCE_INDOMAIN #language en-US "No sources in %s's multicast domain.\r\n" +#string STR_PING6_START #language en-US "Ping %s %d data bytes\r\n" +#string STR_PING6_TIMEOUT #language en-US "Echo request sequence %d timeout.\r\n" +#string STR_PING6_REPLY_INFO #language en-US "%d bytes from %s : icmp_seq=%d ttl=%d time%d~%dms\r\n" +#string STR_PING6_STAT #language en-US "\n%d packets transmitted, %d received, %d%% packet loss, time %dms\r\n" +#string STR_PING6_RTT #language en-US "\nRtt(round trip time) min=%d~%dms max=%d~%dms avg=%d~%dms\r\n" + +#string STR_IFCONFIG6_ERR_IP6CFG_GETDATA #language en-US "Get data of the interface information %hr\r\n" +#string STR_IFCONFIG6_INFO_BREAK #language en-US "-----------------------------------------------------------------" +#string STR_IFCONFIG6_INFO_COLON #language en-US ":" +#string STR_IFCONFIG6_INFO_JOINT #language en-US " >> " +#string STR_IFCONFIG6_INFO_NEWLINE #language en-US "\r\n" +#string STR_IFCONFIG6_INFO_IF_NAME #language en-US "\n%Hname : %s%N\r\n" +#string STR_IFCONFIG6_INFO_POLICY_AUTO #language en-US "%Hpolicy : automatic%N\r\n" +#string STR_IFCONFIG6_INFO_POLICY_MAN #language en-US "%Hpolicy : manual%N\r\n" +#string STR_IFCONFIG6_INFO_DAD_TRANSMITS #language en-US "%Hdad xmits : %d%N\r\n" +#string STR_IFCONFIG6_INFO_INTERFACE_ID_HEAD #language en-US "%Hinterface id : %N" +#string STR_IFCONFIG6_INFO_MAC_ADDR_HEAD #language en-US "%Hmac addr : %N" +#string STR_IFCONFIG6_INFO_MAC_ADDR_BODY #language en-US "%02x" +#string STR_IFCONFIG6_INFO_IP_ADDR_HEAD #language en-US "\n%Hhost addr : %N\r\n" +#string STR_IFCONFIG6_INFO_DNS_ADDR_HEAD #language en-US "\n%Hdns server : %N\r\n" +#string STR_IFCONFIG6_INFO_IP_ADDR_BODY #language en-US "%02x" +#string STR_IFCONFIG6_INFO_IP_ADDR_BODY4BIT #language en-US "%x" +#string STR_IFCONFIG6_INFO_ROUTE_HEAD #language en-US "\n%Hroute table : %N\r\n" +#string STR_IFCONFIG6_INFO_PREFIX_LEN #language en-US "/%d" +#string STR_IFCONFIG6_LINE_HELP #language en-US "Displays or modifies the IPv6 configuration" +#string STR_IFCONFIG6_ERR_LACK_INTERFACE #language en-US "Lack interface name.\r\n" + "Usage: IfConfig6 -s \r\n" + "Example: IfConfig6 -s eth0 auto\r\n" +#string STR_IFCONFIG6_LACK_OPTION #language en-US "Flags lack. Please type 'IfConfig6 -?' for help info.\r\n" +#string STR_IFCONFIG6_CONFLICT_OPTIONS #language en-US "Flags conflict. Please type 'IfConfig6 -?' for help info.\r\n" +#string STR_IFCONFIG6_ERR_LACK_COMMAND #language en-US "Lack interface config option.\r\n" + "Hint: Please type 'IfConfig6 -?' for help info.\r\n" +#string STR_IFCONFIG6_ERR_INVALID_INTERFACE #language en-US "Invalid interface name.\r\n" + "Hint: Use {IfConfig6 -l} to check existing interface names.\r\n" +#string STR_IFCONFIG6_ERR_INVALID_COMMAND #language en-US "Invalid command. Bad command %H%s%N is skipped.\r\n" + "Hint: Incorrect option or arguments. Please type 'IfConfig6 -?' for help info.\r\n" +#string STR_IFCONFIG6_ERR_LACK_ARGUMENTS #language en-US "Lack arguments. Bad command %H%s%N is skipped.\r\n" + "Hint: Please type 'IfConfig6 -?' for help info.\r\n" +#string STR_IFCONFIG6_ERR_LACK_OPTION #language en-US "Lack options.\r\n" + "Hint: Please type 'IfConfig6 -?' for help info.\r\n" +#string STR_IFCONFIG6_ERR_MAN_HOST #language en-US "Manual address configuration failed. Please retry.\r\n" + +#string STR_IFCONFIG6_ERR_MAN_GW #language en-US "Gateway address configuration failed. Please check the argument.\r\n" + +#string STR_IFCONFIG6_ERR_INVALID_IP_CONFIG #language en-US "The IP address is not configurable when the policy is Ip6ConfigPolicyAutomatic.\r\n" + +#string STR_IFCONFIG6_ERR_INVALID_GW_CONFIG #language en-US "The gateway address is not configurable when the policy is Ip6ConfigPolicyAutomatic.\r\n" + +#string STR_IFCONFIG6_ERR_INVALID_DNS_CONFIG #language en-US "The DNS server address is not configurable when the policy is Ip6ConfigPolicyAutomatic.\r\n" + +#string STR_IFCONFIG6_ERR_DUPLICATE_COMMAND #language en-US "Duplicate commands. Bad command %H%s%N is skipped.\r\n" + "Hint: Please type 'IfConfig6 -?' for help info.\r\n" +#string STR_IFCONFIG6_ERR_CONFLICT_COMMAND #language en-US "Conflict commands. Bad command %H%s%N is skipped.\r\n" + "Hint: Please type 'IfConfig6 -?' for help info.\r\n" +#string STR_IFCONFIG6_ERR_UNKNOWN_COMMAND #language en-US "Unknown commands. Bad command %H%s%N is skipped.\r\n" + "Hint: Please type 'IfConfig6 -?' for help info.\r\n" +#string STR_IFCONFIG6_ERR_ADDRESS_FAILED #language en-US "Failed to configure IPv6 address: " + + +#string STR_GET_HELP_PING6 #language en-US "" +".TH ping6 0 "Ping a target machine with UEFI IPv6 network stack."\r\n" +".SH NAME\r\n" +"Ping a target machine with UEFI IPv6 network stack.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"Ping6 [-l size] [-n count] [-s SourceIp] TargetIp\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -l size Send buffer size, in bytes(default=16, min=16, max=32768).\r\n" +" -n count Send request count, (default=10, min=1, max=10000).\r\n" +" -s SourceIp Source IPv6 address.\r\n" +" TargetIp Target IPv6 address.\r\n" +"NOTES:\r\n" +" 1. When TargetIp is a link local address, SourceIp needs to be specified.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"Examples:\r\n" +" * To ping the target host by sending 5 request with 1000 bytes from 2002::1\r\n" +" Shell:\> Ping6 -s 2002::1 2002::2 -l 1000 -n 5\r\n" +" \r\n" +" * To ping the target host with 1000 bytes\r\n" +" Shell:\> Ping6 2002::2 -l 1000\r\n" + +#string STR_GET_HELP_IFCONFIG6 #language en-US "" +".TH ifconfig6 0 "Displays or modifies IPv6 configuration for network interface."\r\n" +".SH NAME\r\n" +"Displays or modifies IPv6 configuration for network interface.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"IfConfig6 -r [Name] | -l [Name] \r\n" +"IfConfig6 -s [dad ] [auto | [man [id ] [host gw ]\r\n" +" [dns ]]]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" Name Adapter name, i.e., eth0\r\n" +" -r [Name] Reconfigure all or specified interface, and set\r\n" +" automatic policy. If specified interface is already\r\n" +" set to automatic,then refresh the IPv6 configuration.\r\n" +" -l [Name] List the configuration of the specified interface.\r\n" +" -s dad Set dad transmits count of the specified interface.\r\n" +" -s auto Set automatic policy of the specified interface.\r\n" +" -s man id Set alternative interface id of the specified \r\n" +" interface. Must under manual policy.\r\n" +" -s man host gw \r\n" +" Set static host IP and gateway address of the\r\n" +" specified interface. Must under manual policy.\r\n" +" -s man dns Set DNS server IP addresses of the specified\r\n" +" interface.Must under manual policy.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To list the configuration for the interface eth0:\r\n" +" Shell:\> ifConfig6 -l eth0\r\n" +" \r\n" +" * To use automatic configuration to request the IPv6 address configuration\r\n" +" dynamically for the interface eth0:\r\n" +" Shell:\> ifconfig6 -s eth0 auto\r\n" +" \r\n" +" * To set the dad transmits count for eth0 under automatic policy:\r\n" +" Shell:\> ifconfig6 -s eth0 auto dad 10\r\n" +" \r\n" +" * To set the alternative interface id of eth0 under manual policy:\r\n" +" Shell:\> ifconfig6 -s eth0 man id ff:dd:aa:88:66:cc\r\n" +" \r\n" +" * To use the static IP6 addresses configuration for the interface eth0,\r\n" +" and this configuration survives the network reload:\r\n" +" Shell:\> ifconfig6 -s eth0 man host 2002::1/64 2002::2/64 gw 2002::3/64\r\n" diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/ShellPkg.ci.yaml b/src/VBox/Devices/EFI/Firmware/ShellPkg/ShellPkg.ci.yaml new file mode 100644 index 00000000..42d0f519 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/ShellPkg.ci.yaml @@ -0,0 +1,70 @@ +## @file +# CI configuration for ShellPkg +# +# Copyright (c) Microsoft Corporation +# Copyright (c) 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "LicenseCheck": { + "IgnoreFiles": [] + }, + "EccCheck": { + ## Exception sample looks like below: + ## "ExceptionList": [ + ## "", "" + ## ] + "ExceptionList": [ + ], + ## Both file path and directory path are accepted. + "IgnoreFiles": [ + ] + }, + "CompilerPlugin": { + "DscPath": "ShellPkg.dsc" + }, + "CharEncodingCheck": { + "IgnoreFiles": [] + }, + "DependencyCheck": { + "AcceptableDependencies": [ + "MdePkg/MdePkg.dec", + "MdeModulePkg/MdeModulePkg.dec", + "ShellPkg/ShellPkg.dec", + "NetworkPkg/NetworkPkg.dec" + ], + # For host based unit tests + "AcceptableDependencies-HOST_APPLICATION":[], + # For UEFI shell based apps + "AcceptableDependencies-UEFI_APPLICATION":[], + "IgnoreInf": [] + }, + "DscCompleteCheck": { + "DscPath": "ShellPkg.dsc", + "IgnoreInf": [ + "ShellPkg/Application/ShellCTestApp/ShellCTestApp.inf", + "ShellPkg/Application/ShellExecTestApp/SA.inf", + "ShellPkg/Application/ShellSortTestApp/ShellSortTestApp.inf" + ] + }, + "GuidCheck": { + "IgnoreGuidName": [], + "IgnoreGuidValue": [], + "IgnoreFoldersAndFiles": [], + "IgnoreDuplicates": [ + "Shell=gUefiShellFileGuid", # by design + ] + }, + "LibraryClassCheck": { + "IgnoreHeaderFile": [] + }, + + ## options defined ci/Plugin/SpellCheck + "SpellCheck": { + "AuditOnly": True, # Fails test but run in AuditOnly mode to collect log + "IgnoreFiles": [], # use gitignore syntax to ignore errors in matching files + "ExtendWords": [], # words to extend to the dictionary for this package + "IgnoreStandardPaths": [], # Standard Plugin defined paths that should be ignore + "AdditionalIncludePaths": [] # Additional paths to spell check (wildcards supported) + } +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/ShellPkg.dec b/src/VBox/Devices/EFI/Firmware/ShellPkg/ShellPkg.dec new file mode 100644 index 00000000..bd64b961 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/ShellPkg.dec @@ -0,0 +1,138 @@ +## @file ShellPkg.dec +# This Package provides all definitions for EFI and UEFI Shell +# +# (C) Copyright 2013-2014 Hewlett-Packard Development Company, L.P.
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+# Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + DEC_SPECIFICATION = 0x00010005 + PACKAGE_NAME = ShellPkg + PACKAGE_GUID = C1014BB7-4092-43D4-984F-0738EB424DBF + PACKAGE_VERSION = 1.02 + +[Includes] + Include + +[LibraryClasses] + ## @libraryclass Provides most Shell APIs. Only available for Shell applications + ShellLib|Include/Library/ShellLib.h + + ## @libraryclass Provides shell internal support Only available for shell internal commands + ShellCommandLib|Include/Library/ShellCommandLib.h + + ## @libraryclass Allows for a shell application to have a C style entry point + ShellCEntryLib|Include/Library/ShellCEntryLib.h + + ## @libraryclass Provides advanced parsing functions + HandleParsingLib|Include/Library/HandleParsingLib.h + + ## @libraryclass provides BCFG command + BcfgCommandLib|Include/Library/BcfgCommandLib.h + + ## @libraryclass provides the AcpiView command + AcpiViewCommandLib|Include/Library/AcpiViewCommandLib.h + +[Guids] + gEfiShellEnvironment2ExtGuid = {0xd2c18636, 0x40e5, 0x4eb5, {0xa3, 0x1b, 0x36, 0x69, 0x5f, 0xd4, 0x2c, 0x87}} + gEfiShellPkgTokenSpaceGuid = {0x171e9188, 0x31d3, 0x40f5, {0xb1, 0x0c, 0x53, 0x9b, 0x2d, 0xb9, 0x40, 0xcd}} + gShellVariableGuid = {0x158def5a, 0xf656, 0x419c, {0xb0, 0x27, 0x7a, 0x31, 0x92, 0xc0, 0x79, 0xd2}} + gShellMapGuid = {0x51271e13, 0x7de3, 0x43af, {0x8b, 0xc2, 0x71, 0xad, 0x3b, 0x82, 0x43, 0x25}} + gShellAliasGuid = {0x0053d9d6, 0x2659, 0x4599, {0xa2, 0x6b, 0xef, 0x45, 0x36, 0xe6, 0x31, 0xa9}} + gHandleParsingHiiGuid = {0xb8969637, 0x81de, 0x43af, {0xbc, 0x9a, 0x24, 0xd9, 0x89, 0x13, 0xf2, 0xf6}} + gShellDebug1HiiGuid = {0x25f200aa, 0xd3cb, 0x470a, {0xbf, 0x51, 0xe7, 0xd1, 0x62, 0xd2, 0x2e, 0x6f}} + gShellDriver1HiiGuid = {0xaf0b742, 0x63ec, 0x45bd, {0x8d, 0xb6, 0x71, 0xad, 0x7f, 0x2f, 0xe8, 0xe8}} + gShellInstall1HiiGuid = {0x7d574d54, 0xd364, 0x4d4a, {0x95, 0xe3, 0x49, 0x45, 0xdb, 0x7a, 0xd3, 0xee}} + gShellLevel1HiiGuid = {0xdec5daa4, 0x6781, 0x4820, {0x9c, 0x63, 0xa7, 0xb0, 0xe4, 0xf1, 0xdb, 0x31}} + gShellLevel2HiiGuid = {0xf95a7ccc, 0x4c55, 0x4426, {0xa7, 0xb4, 0xdc, 0x89, 0x61, 0x95, 0xb, 0xae}} + gShellLevel3HiiGuid = {0x4344558d, 0x4ef9, 0x4725, {0xb1, 0xe4, 0x33, 0x76, 0xe8, 0xd6, 0x97, 0x4f}} + gShellNetwork1HiiGuid = {0xf3d301bb, 0xf4a5, 0x45a8, {0xb0, 0xb7, 0xfa, 0x99, 0x9c, 0x62, 0x37, 0xae}} + gShellNetwork2HiiGuid = {0x174b2b5, 0xf505, 0x4b12, {0xaa, 0x60, 0x59, 0xdf, 0xf8, 0xd6, 0xea, 0x37}} + gShellTftpHiiGuid = {0x738a9314, 0x82c1, 0x4592, {0x8f, 0xf7, 0xc1, 0xbd, 0xf1, 0xb2, 0x0e, 0xd4}} + gShellHttpHiiGuid = {0x390f84b3, 0x221c, 0x4d9e, {0xb5, 0x06, 0x6d, 0xb9, 0x42, 0x3e, 0x0a, 0x7e}} + gShellBcfgHiiGuid = {0x5f5f605d, 0x1583, 0x4a2d, {0xa6, 0xb2, 0xeb, 0x12, 0xda, 0xb4, 0xa2, 0xb6}} + gShellAcpiViewHiiGuid = {0xda8ccdf4, 0xed8f, 0x4ffc, {0xb5, 0xef, 0x2e, 0xf5, 0x5e, 0x24, 0x93, 0x2a}} + # FILE_GUID as defined in ShellPkg/Application/Shell/Shell.inf + gUefiShellFileGuid = {0x7c04a583, 0x9e3e, 0x4f1c, {0xad, 0x65, 0xe0, 0x52, 0x68, 0xd0, 0xb4, 0xd1}} + +[Protocols] + gEfiShellEnvironment2Guid = {0x47c7b221, 0xc42a, 0x11d2, {0x8e, 0x57, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}} + gEfiShellInterfaceGuid = {0x47c7b223, 0xc42a, 0x11d2, {0x8e, 0x57, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}} + +[PcdsFeatureFlag] + ## This flag is used to control whether the shell includes NT32 platform Guids + # and thereby prevents dependancy on that Pkg + gEfiShellPkgTokenSpaceGuid.PcdShellIncludeNtGuids|TRUE|BOOLEAN|0x0000000E + + ## This flag is used to control HII required by the shell + gEfiShellPkgTokenSpaceGuid.PcdShellRequireHiiPlatform|TRUE|BOOLEAN|0x00000003 + + ## This flag is used to control HII required by the shell + gEfiShellPkgTokenSpaceGuid.PcdShellSupportFrameworkHii|FALSE|BOOLEAN|0x00000004 + + ## This flag forces the shell to present a user console. Allows for earlier debugging of platforms. + gEfiShellPkgTokenSpaceGuid.PcdShellForceConsole|FALSE|BOOLEAN|0x0000000F + +[PcdsFixedAtBuild] + ## This flag is used to control initialization of the shell library + # This should be FALSE for compiling the shell application itself only. + # This should be FALSE for compiling the dynamic command drivers. + gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|TRUE|BOOLEAN|0x00000005 + + ## This is the max buffer for ShellLib and internal Shell printings. + gEfiShellPkgTokenSpaceGuid.PcdShellPrintBufferSize|16000|UINT16|0x0000000C + + ## This flag is used to control the commands available in the shell + gEfiShellPkgTokenSpaceGuid.PcdShellSupportLevel|3|UINT8|0x00000001 + + ## This flag is used to control the profiles available in the shell + # don't forget to update the text file if you change this. + # bit 0 = Drivers1 + # bit 1 = Debug1 + # bit 2 = Install1 + # bit 3 = Network1 + # bit 4 = Network2 + gEfiShellPkgTokenSpaceGuid.PcdShellProfileMask|0xFF|UINT8|0x0000000D + + ## This is the character count for allocation for consistent mappings + gEfiShellPkgTokenSpaceGuid.PcdShellMapNameLength|50|UINT8|0x00000009 + + ## This determines how many bytes are read out of files at a time for file operations (type, copy, etc...) + gEfiShellPkgTokenSpaceGuid.PcdShellFileOperationSize|0x1000|UINT32|0x0000000A + + ## This determines the max count of history commands + gEfiShellPkgTokenSpaceGuid.PcdShellMaxHistoryCommandCount|0x0020|UINT16|0x00000014 + +[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx] + ## This flag is used to control the protocols produced by the shell + # If TRUE the shell will produce EFI_SHELL_ENVIRONMENT2 and EFI_SHELL_INTERFACE + gEfiShellPkgTokenSpaceGuid.PcdShellSupportOldProtocols|FALSE|BOOLEAN|0x00000002 + + ## this flag determines whether Page Break (-b) defaults to on or off in the shell + gEfiShellPkgTokenSpaceGuid.PcdShellPageBreakDefault|FALSE|BOOLEAN|0x00000006 + + ## this flag determines whether insert mode for typing is default (FALSE means typeover) + gEfiShellPkgTokenSpaceGuid.PcdShellInsertModeDefault|TRUE|BOOLEAN|0x00000007 + + ## this flag determines the default number of screens kept for history log. + # the spec defines 3 as the minimum + gEfiShellPkgTokenSpaceGuid.PcdShellScreenLogCount|3|UINT8|0x00000008 + + ## Unicode string of the shell supplier + gEfiShellPkgTokenSpaceGuid.PcdShellSupplier|L"EDK II"|VOID*|0x00000010 + + ## Do extended decode of USB for determining media type + gEfiShellPkgTokenSpaceGuid.PcdUsbExtendedDecode|TRUE|BOOLEAN|0x00000011 + + ## Do iSCSI decode for map names. + # This is disabled by default due to the length of generated strings + gEfiShellPkgTokenSpaceGuid.PcdShellDecodeIScsiMapNames|FALSE|BOOLEAN|0x00000012 + + ## Controls Extended decode for Vendor device path nodes for map names. + # Up to this many bytes of vendor specific data will be used. Default is 0 + # (disabled). + gEfiShellPkgTokenSpaceGuid.PcdShellVendorExtendedDecode|0|UINT32|0x00000013 diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/ShellPkg.dsc b/src/VBox/Devices/EFI/Firmware/ShellPkg/ShellPkg.dsc new file mode 100644 index 00000000..ad7d0be5 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/ShellPkg.dsc @@ -0,0 +1,158 @@ +## @file +# Shell Package +# +# Copyright (c) 2007 - 2021, Intel Corporation. All rights reserved.
+# Copyright (c) 2018 - 2020, Arm Limited. All rights reserved.
+# Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + PLATFORM_NAME = Shell + PLATFORM_GUID = E1DC9BF8-7013-4c99-9437-795DAA45F3BD + PLATFORM_VERSION = 1.02 + DSC_SPECIFICATION = 0x00010006 + OUTPUT_DIRECTORY = Build/Shell + SUPPORTED_ARCHITECTURES = IA32|X64|EBC|ARM|AARCH64|RISCV64 + BUILD_TARGETS = DEBUG|RELEASE|NOOPT + SKUID_IDENTIFIER = DEFAULT + +!include MdePkg/MdeLibs.dsc.inc + +[LibraryClasses.common] + UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf + UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf + UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf + DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLibOptionalDevicePathProtocol.inf +!if $(TARGET) == RELEASE + DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf +!else + DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf +!endif + DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + UefiLib|MdePkg/Library/UefiLib/UefiLib.inf + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf + SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf + UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf + UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf + HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf + !include NetworkPkg/NetworkLibs.dsc.inc + + ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf + ShellCommandLib|ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf + ShellCEntryLib|ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf + HandleParsingLib|ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf + OrderedCollectionLib|MdePkg/Library/BaseOrderedCollectionRedBlackTreeLib/BaseOrderedCollectionRedBlackTreeLib.inf + + PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf + BcfgCommandLib|ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf + AcpiViewCommandLib|ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf + IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf + + UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf + HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf + PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf + DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf + DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf + ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf + +[LibraryClasses.ARM,LibraryClasses.AARCH64] + # + # It is not possible to prevent the ARM compiler for generic intrinsic functions. + # This library provides the instrinsic functions generate by a given compiler. + # [LibraryClasses.ARM] and NULL mean link this library into all ARM images. + # + NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf + + # Add support for GCC stack protector + NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf + +[PcdsFixedAtBuild] + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xFF + gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|16000 +!ifdef $(NO_SHELL_PROFILES) + gEfiShellPkgTokenSpaceGuid.PcdShellProfileMask|0x00 +!endif #$(NO_SHELL_PROFILES) + +[Components] + # + # Build all the libraries when building this package. + # This helps developers test changes and how they affect the package. + # + ShellPkg/Library/UefiShellLib/UefiShellLib.inf + ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf + ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf + ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf + ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf + ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf + ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf + ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf + ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf + ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf + ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.inf + ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf + ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf + ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.inf + + ShellPkg/Application/Shell/Shell.inf { + + gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE + + NULL|ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf + NULL|ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf + NULL|ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf +!ifndef $(NO_SHELL_PROFILES) + NULL|ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf + NULL|ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.inf + NULL|ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf + NULL|ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf + NULL|ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.inf +!endif #$(NO_SHELL_PROFILES) + } + + # + # Build a second version of the shell with all commands integrated + # + ShellPkg/Application/Shell/Shell.inf { + + FILE_GUID = EA4BB293-2D7F-4456-A681-1F22F42CD0BC + + gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE + + NULL|ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf + NULL|ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf + NULL|ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf + NULL|ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf + NULL|ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.inf + NULL|ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf + NULL|ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf + NULL|ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.inf + NULL|ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf + } + + ShellPkg/DynamicCommand/TftpDynamicCommand/TftpDynamicCommand.inf { + + gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE + } + ShellPkg/DynamicCommand/TftpDynamicCommand/TftpApp.inf + ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand.inf { + + gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE + } + ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.inf + ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicCommand.inf { + + gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE + } + ShellPkg/DynamicCommand/DpDynamicCommand/DpApp.inf + ShellPkg/Application/AcpiViewApp/AcpiViewApp.inf + +[BuildOptions] + *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES -- cgit v1.2.3