From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- .../Library/UefiShellCommandLib/ConsistMapping.c | 1692 +++++++++++++++++ .../UefiShellCommandLib/UefiShellCommandLib.c | 1911 ++++++++++++++++++++ .../UefiShellCommandLib/UefiShellCommandLib.h | 65 + .../UefiShellCommandLib/UefiShellCommandLib.inf | 64 + 4 files changed, 3732 insertions(+) create mode 100755 roms/edk2/ShellPkg/Library/UefiShellCommandLib/ConsistMapping.c create mode 100644 roms/edk2/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c create mode 100644 roms/edk2/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.h create mode 100644 roms/edk2/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf (limited to 'roms/edk2/ShellPkg/Library/UefiShellCommandLib') diff --git a/roms/edk2/ShellPkg/Library/UefiShellCommandLib/ConsistMapping.c b/roms/edk2/ShellPkg/Library/UefiShellCommandLib/ConsistMapping.c new file mode 100755 index 000000000..8278388f3 --- /dev/null +++ b/roms/edk2/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/roms/edk2/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c b/roms/edk2/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c new file mode 100644 index 000000000..345808a1e --- /dev/null +++ b/roms/edk2/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c @@ -0,0 +1,1911 @@ +/** @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; +} diff --git a/roms/edk2/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.h b/roms/edk2/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.h new file mode 100644 index 000000000..8ecc2f6bf --- /dev/null +++ b/roms/edk2/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.h @@ -0,0 +1,65 @@ +/** @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 + +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; + + +#endif //_UEFI_COMMAND_LIB_INTERNAL_HEADER_ + diff --git a/roms/edk2/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf b/roms/edk2/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf new file mode 100644 index 000000000..a1b5601c9 --- /dev/null +++ b/roms/edk2/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf @@ -0,0 +1,64 @@ +## @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 + +[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 -- cgit