Home | History | Annotate | Download | only in UefiShellDebug1CommandsLib
      1 /** @file
      2   Main file for Mm shell Debug1 function.
      3 
      4   (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
      5   Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR>
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "UefiShellDebug1CommandsLib.h"
     17 #include <Library/ShellLib.h>
     18 #include <Library/IoLib.h>
     19 #include <Protocol/PciRootBridgeIo.h>
     20 #include <Protocol/DeviceIo.h>
     21 
     22 typedef enum {
     23   ShellMmMemory,
     24   ShellMmMemoryMappedIo,
     25   ShellMmIo,
     26   ShellMmPci,
     27   ShellMmPciExpress
     28 } SHELL_MM_ACCESS_TYPE;
     29 
     30 CONST UINT16 mShellMmAccessTypeStr[] = {
     31   STRING_TOKEN (STR_MM_MEM),
     32   STRING_TOKEN (STR_MM_MMIO),
     33   STRING_TOKEN (STR_MM_IO),
     34   STRING_TOKEN (STR_MM_PCI),
     35   STRING_TOKEN (STR_MM_PCIE)
     36 };
     37 
     38 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
     39   {L"-mmio", TypeFlag},
     40   {L"-mem", TypeFlag},
     41   {L"-io", TypeFlag},
     42   {L"-pci", TypeFlag},
     43   {L"-pcie", TypeFlag},
     44   {L"-n", TypeFlag},
     45   {L"-w", TypeValue},
     46   {NULL, TypeMax}
     47   };
     48 
     49 CONST UINT64 mShellMmMaxNumber[] = {
     50   0, MAX_UINT8, MAX_UINT16, 0, MAX_UINT32, 0, 0, 0, MAX_UINT64
     51 };
     52 CONST EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH mShellMmRootBridgeIoWidth[] = {
     53   0, EfiPciWidthUint8, EfiPciWidthUint16, 0, EfiPciWidthUint32, 0, 0, 0, EfiPciWidthUint64
     54 };
     55 CONST EFI_CPU_IO_PROTOCOL_WIDTH mShellMmCpuIoWidth[] = {
     56   0, EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, 0, EfiCpuIoWidthUint32, 0, 0, 0, EfiCpuIoWidthUint64
     57 };
     58 
     59 /**
     60   Extract the PCI segment, bus, device, function, register from
     61   from a SHELL_MM_PCI or SHELL_MM_PCIE format of address..
     62 
     63   @param[in]  PciFormat      Whether the address is of PCI format of PCIE format.
     64   @param[in]  Address        SHELL_MM_PCI or SHELL_MM_PCIE address.
     65   @param[out] Segment        PCI segment number.
     66   @param[out] Bus            PCI bus number.
     67   @param[out] Device         PCI device number.
     68   @param[out] Function       PCI function number.
     69   @param[out] Register       PCI register offset.
     70 **/
     71 VOID
     72 EFIAPI
     73 ShellMmDecodePciAddress (
     74   IN BOOLEAN                PciFormat,
     75   IN UINT64                 Address,
     76   OUT UINT32                *Segment,
     77   OUT UINT8                 *Bus,
     78   OUT UINT8                 *Device,   OPTIONAL
     79   OUT UINT8                 *Function, OPTIONAL
     80   OUT UINT32                *Register  OPTIONAL
     81   )
     82 {
     83   if (PciFormat) {
     84     //
     85     // PCI Configuration Space.The address will have the format 0x000000ssbbddffrr,
     86     // where ss = Segment, bb = Bus, dd = Device, ff = Function and rr = Register.
     87     //
     88     *Segment = (UINT32) (RShiftU64 (Address, 32) & 0xFF);
     89     *Bus = (UINT8) (((UINT32) Address) >> 24);
     90 
     91     if (Device != NULL) {
     92       *Device = (UINT8) (((UINT32) Address) >> 16);
     93     }
     94     if (Function != NULL) {
     95       *Function = (UINT8) (((UINT32) Address) >> 8);
     96     }
     97     if (Register != NULL) {
     98       *Register = (UINT8) Address;
     99     }
    100   } else {
    101     //
    102     // PCI Express Configuration Space.The address will have the format 0x0000000ssbbddffrrr,
    103     // where ss = Segment, bb = Bus, dd = Device, ff = Function and rrr = Register.
    104     //
    105     *Segment = (UINT32) (RShiftU64 (Address, 36) & 0xFF);
    106     *Bus = (UINT8) RShiftU64 (Address, 28);
    107     if (Device != NULL) {
    108       *Device = (UINT8) (((UINT32) Address) >> 20);
    109     }
    110     if (Function != NULL) {
    111       *Function = (UINT8) (((UINT32) Address) >> 12);
    112     }
    113     if (Register != NULL) {
    114       *Register = (UINT32) (Address & 0xFFF);
    115     }
    116   }
    117 }
    118 
    119 /**
    120   Read or write some data from or into the Address.
    121 
    122   @param[in]      AccessType      Access type.
    123   @param[in]      PciRootBridgeIo PciRootBridgeIo instance.
    124   @param[in]      CpuIo           CpuIo instance.
    125   @param[in]      Read            TRUE for read, FALSE for write.
    126   @param[in]      Addresss        The memory location to access.
    127   @param[in]      Size            The size of Buffer in Width sized units.
    128   @param[in, out] Buffer          The buffer to read into or write from.
    129 **/
    130 VOID
    131 ShellMmAccess (
    132   IN     SHELL_MM_ACCESS_TYPE            AccessType,
    133   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
    134   IN     EFI_CPU_IO2_PROTOCOL            *CpuIo,
    135   IN     BOOLEAN                         Read,
    136   IN     UINT64                          Address,
    137   IN     UINTN                           Size,
    138   IN OUT VOID                            *Buffer
    139   )
    140 {
    141   EFI_STATUS                                Status;
    142   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM    RootBridgeIoMem;
    143   EFI_CPU_IO_PROTOCOL_IO_MEM                CpuIoMem;
    144   UINT32                                    Segment;
    145   UINT8                                     Bus;
    146   UINT8                                     Device;
    147   UINT8                                     Function;
    148   UINT32                                    Register;
    149 
    150   if (AccessType == ShellMmMemory) {
    151     if (Read) {
    152       CopyMem (Buffer, (VOID *) (UINTN) Address, Size);
    153     } else {
    154       CopyMem ((VOID *) (UINTN) Address, Buffer, Size);
    155     }
    156   } else {
    157     RootBridgeIoMem = NULL;
    158     CpuIoMem = NULL;
    159     switch (AccessType) {
    160     case ShellMmPci:
    161     case ShellMmPciExpress:
    162       ASSERT (PciRootBridgeIo != NULL);
    163       ShellMmDecodePciAddress ((BOOLEAN) (AccessType == ShellMmPci), Address, &Segment, &Bus, &Device, &Function, &Register);
    164       if (Read) {
    165         Status = PciRootBridgeIo->Pci.Read (
    166           PciRootBridgeIo, mShellMmRootBridgeIoWidth[Size],
    167           EFI_PCI_ADDRESS (Bus, Device, Function, Register),
    168           1, Buffer
    169           );
    170       } else {
    171         Status = PciRootBridgeIo->Pci.Write (
    172           PciRootBridgeIo, mShellMmRootBridgeIoWidth[Size],
    173           EFI_PCI_ADDRESS (Bus, Device, Function, Register),
    174           1, Buffer
    175           );
    176       }
    177       ASSERT_EFI_ERROR (Status);
    178       return;
    179 
    180     case ShellMmMemoryMappedIo:
    181       if (PciRootBridgeIo != NULL) {
    182         RootBridgeIoMem = Read ? PciRootBridgeIo->Mem.Read : PciRootBridgeIo->Mem.Write;
    183       }
    184       if (CpuIo != NULL) {
    185         CpuIoMem = Read ? CpuIo->Mem.Read : CpuIo->Mem.Write;
    186       }
    187       break;
    188 
    189     case ShellMmIo:
    190       if (PciRootBridgeIo != NULL) {
    191         RootBridgeIoMem = Read ? PciRootBridgeIo->Io.Read : PciRootBridgeIo->Io.Write;
    192       }
    193       if (CpuIo != NULL) {
    194         CpuIoMem = Read ? CpuIo->Io.Read : CpuIo->Io.Write;
    195       }
    196       break;
    197     default:
    198       ASSERT (FALSE);
    199       break;
    200     }
    201 
    202     Status = EFI_UNSUPPORTED;
    203     if (RootBridgeIoMem != NULL) {
    204       Status = RootBridgeIoMem (PciRootBridgeIo, mShellMmRootBridgeIoWidth[Size], Address, 1, Buffer);
    205     }
    206     if (EFI_ERROR (Status) && (CpuIoMem != NULL)) {
    207       Status = CpuIoMem (CpuIo, mShellMmCpuIoWidth[Size], Address, 1, Buffer);
    208     }
    209 
    210     if (EFI_ERROR (Status)) {
    211       if (AccessType == ShellMmIo) {
    212         switch (Size) {
    213         case 1:
    214           if (Read) {
    215             *(UINT8 *) Buffer = IoRead8 ((UINTN) Address);
    216           } else {
    217             IoWrite8 ((UINTN) Address, *(UINT8 *) Buffer);
    218           }
    219           break;
    220         case 2:
    221           if (Read) {
    222             *(UINT16 *) Buffer = IoRead16 ((UINTN) Address);
    223           } else {
    224             IoWrite16 ((UINTN) Address, *(UINT16 *) Buffer);
    225           }
    226           break;
    227         case 4:
    228           if (Read) {
    229             *(UINT32 *) Buffer = IoRead32 ((UINTN) Address);
    230           } else {
    231             IoWrite32 ((UINTN) Address, *(UINT32 *) Buffer);
    232           }
    233           break;
    234         case 8:
    235           if (Read) {
    236             *(UINT64 *) Buffer = IoRead64 ((UINTN) Address);
    237           } else {
    238             IoWrite64 ((UINTN) Address, *(UINT64 *) Buffer);
    239           }
    240           break;
    241         default:
    242           ASSERT (FALSE);
    243           break;
    244         }
    245       } else {
    246         switch (Size) {
    247         case 1:
    248           if (Read) {
    249             *(UINT8 *) Buffer = MmioRead8 ((UINTN) Address);
    250           } else {
    251             MmioWrite8 ((UINTN) Address, *(UINT8 *) Buffer);
    252           }
    253           break;
    254         case 2:
    255           if (Read) {
    256             *(UINT16 *) Buffer = MmioRead16 ((UINTN) Address);
    257           } else {
    258             MmioWrite16 ((UINTN) Address, *(UINT16 *) Buffer);
    259           }
    260           break;
    261         case 4:
    262           if (Read) {
    263             *(UINT32 *) Buffer = MmioRead32 ((UINTN) Address);
    264           } else {
    265             MmioWrite32 ((UINTN) Address, *(UINT32 *) Buffer);
    266           }
    267           break;
    268         case 8:
    269           if (Read) {
    270             *(UINT64 *) Buffer = MmioRead64 ((UINTN) Address);
    271           } else {
    272             MmioWrite64 ((UINTN) Address, *(UINT64 *) Buffer);
    273           }
    274           break;
    275         default:
    276           ASSERT (FALSE);
    277           break;
    278         }
    279       }
    280     }
    281   }
    282 }
    283 
    284 /**
    285   Find the CpuIo instance and PciRootBridgeIo instance in the platform.
    286   If there are multiple PciRootBridgeIo instances, the instance which manages
    287   the Address is returned.
    288 
    289   @param[in]  AccessType      Access type.
    290   @param[in]  Address         Address to access.
    291   @param[out] CpuIo           Return the CpuIo instance.
    292   @param[out] PciRootBridgeIo Return the proper PciRootBridgeIo instance.
    293 
    294   @retval TRUE  There are PciRootBridgeIo instances in the platform.
    295   @retval FALSE There isn't PciRootBridgeIo instance in the platform.
    296 **/
    297 BOOLEAN
    298 ShellMmLocateIoProtocol (
    299   IN SHELL_MM_ACCESS_TYPE             AccessType,
    300   IN UINT64                           Address,
    301   OUT EFI_CPU_IO2_PROTOCOL            **CpuIo,
    302   OUT EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL **PciRootBridgeIo
    303   )
    304 {
    305   EFI_STATUS                          Status;
    306   UINTN                               Index;
    307   UINTN                               HandleCount;
    308   EFI_HANDLE                          *HandleBuffer;
    309   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL     *Io;
    310   UINT32                              Segment;
    311   UINT8                               Bus;
    312   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   *Descriptors;
    313 
    314   Status = gBS->LocateProtocol (&gEfiCpuIo2ProtocolGuid, NULL, (VOID **) CpuIo);
    315   if (EFI_ERROR (Status)) {
    316     *CpuIo = NULL;
    317   }
    318 
    319   *PciRootBridgeIo = NULL;
    320   HandleBuffer     = NULL;
    321   Status = gBS->LocateHandleBuffer (
    322                   ByProtocol,
    323                   &gEfiPciRootBridgeIoProtocolGuid,
    324                   NULL,
    325                   &HandleCount,
    326                   &HandleBuffer
    327                   );
    328   if (EFI_ERROR (Status) || (HandleCount == 0) || (HandleBuffer == NULL)) {
    329     return FALSE;
    330   }
    331 
    332   Segment = 0;
    333   Bus     = 0;
    334   if ((AccessType == ShellMmPci) || (AccessType == ShellMmPciExpress)) {
    335     ShellMmDecodePciAddress ((BOOLEAN) (AccessType == ShellMmPci), Address, &Segment, &Bus, NULL, NULL, NULL);
    336   }
    337 
    338   //
    339   // Find the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL of the specified segment & bus number
    340   //
    341   for (Index = 0; (Index < HandleCount) && (*PciRootBridgeIo == NULL); Index++) {
    342     Status = gBS->HandleProtocol (
    343                     HandleBuffer[Index],
    344                     &gEfiPciRootBridgeIoProtocolGuid,
    345                     (VOID *) &Io
    346                     );
    347     if (EFI_ERROR (Status)) {
    348       continue;
    349     }
    350 
    351     if ((((AccessType == ShellMmPci) || (AccessType == ShellMmPciExpress)) && (Io->SegmentNumber == Segment)) ||
    352         ((AccessType == ShellMmIo) || (AccessType == ShellMmMemoryMappedIo))
    353         ) {
    354       Status = Io->Configuration (Io, (VOID **) &Descriptors);
    355       if (!EFI_ERROR (Status)) {
    356         while (Descriptors->Desc != ACPI_END_TAG_DESCRIPTOR) {
    357           //
    358           // Compare the segment and bus range for PCI/PCIE access
    359           //
    360           if ((Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) &&
    361               ((AccessType == ShellMmPci) || (AccessType == ShellMmPciExpress)) &&
    362               ((Bus >= Descriptors->AddrRangeMin) && (Bus <= Descriptors->AddrRangeMax))
    363               ) {
    364             *PciRootBridgeIo = Io;
    365             break;
    366 
    367           //
    368           // Compare the address range for MMIO/IO access
    369           //
    370           } else if ((((Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_IO) && (AccessType == ShellMmIo)) ||
    371                       ((Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) && (AccessType == ShellMmMemoryMappedIo))
    372                       ) && ((Address >= Descriptors->AddrRangeMin) && (Address <= Descriptors->AddrRangeMax))
    373                      ) {
    374             *PciRootBridgeIo = Io;
    375             break;
    376           }
    377           Descriptors++;
    378         }
    379       }
    380     }
    381   }
    382   if (HandleBuffer != NULL) {
    383     FreePool (HandleBuffer);
    384   }
    385 
    386   return TRUE;
    387 }
    388 
    389 /**
    390   Function for 'mm' command.
    391 
    392   @param[in] ImageHandle  Handle to the Image (NULL if Internal).
    393   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
    394 **/
    395 SHELL_STATUS
    396 EFIAPI
    397 ShellCommandRunMm (
    398   IN EFI_HANDLE        ImageHandle,
    399   IN EFI_SYSTEM_TABLE  *SystemTable
    400   )
    401 {
    402   EFI_STATUS                            Status;
    403   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *PciRootBridgeIo;
    404   EFI_CPU_IO2_PROTOCOL                  *CpuIo;
    405   UINT64                                Address;
    406   UINT64                                Value;
    407   SHELL_MM_ACCESS_TYPE                  AccessType;
    408   UINT64                                Buffer;
    409   UINTN                                 Index;
    410   UINTN                                 Size;
    411   BOOLEAN                               Complete;
    412   CHAR16                                *InputStr;
    413   BOOLEAN                               Interactive;
    414   LIST_ENTRY                            *Package;
    415   CHAR16                                *ProblemParam;
    416   SHELL_STATUS                          ShellStatus;
    417   CONST CHAR16                          *Temp;
    418   BOOLEAN                               HasPciRootBridgeIo;
    419 
    420   Value = 0;
    421   Address = 0;
    422   ShellStatus = SHELL_SUCCESS;
    423   InputStr = NULL;
    424   Size = 1;
    425   AccessType = ShellMmMemory;
    426 
    427   //
    428   // Parse arguments
    429   //
    430   Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
    431   if (EFI_ERROR (Status)) {
    432     if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
    433       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"mm", ProblemParam);
    434       FreePool (ProblemParam);
    435       ShellStatus = SHELL_INVALID_PARAMETER;
    436       goto Done;
    437     } else {
    438       ASSERT (FALSE);
    439     }
    440   } else {
    441     if (ShellCommandLineGetCount (Package) < 2) {
    442       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"mm");
    443       ShellStatus = SHELL_INVALID_PARAMETER;
    444       goto Done;
    445     } else if (ShellCommandLineGetCount (Package) > 3) {
    446       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mm");
    447       ShellStatus = SHELL_INVALID_PARAMETER;
    448       goto Done;
    449     } else if (ShellCommandLineGetFlag (Package, L"-w") && ShellCommandLineGetValue (Package, L"-w") == NULL) {
    450       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDebug1HiiHandle, L"mm", L"-w");
    451       ShellStatus = SHELL_INVALID_PARAMETER;
    452       goto Done;
    453     } else {
    454       if (ShellCommandLineGetFlag (Package, L"-mmio")) {
    455         AccessType = ShellMmMemoryMappedIo;
    456         if (ShellCommandLineGetFlag (Package, L"-mem")
    457             || ShellCommandLineGetFlag (Package, L"-io")
    458             || ShellCommandLineGetFlag (Package, L"-pci")
    459             || ShellCommandLineGetFlag (Package, L"-pcie")
    460             ) {
    461           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mm");
    462           ShellStatus = SHELL_INVALID_PARAMETER;
    463           goto Done;
    464         }
    465       } else if (ShellCommandLineGetFlag (Package, L"-mem")) {
    466         AccessType = ShellMmMemory;
    467         if (ShellCommandLineGetFlag (Package, L"-io")
    468             || ShellCommandLineGetFlag (Package, L"-pci")
    469             || ShellCommandLineGetFlag (Package, L"-pcie")
    470             ) {
    471           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mm");
    472           ShellStatus = SHELL_INVALID_PARAMETER;
    473           goto Done;
    474         }
    475       } else if (ShellCommandLineGetFlag (Package, L"-io")) {
    476         AccessType = ShellMmIo;
    477         if (ShellCommandLineGetFlag (Package, L"-pci")
    478             || ShellCommandLineGetFlag (Package, L"-pcie")
    479             ) {
    480           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mm");
    481           ShellStatus = SHELL_INVALID_PARAMETER;
    482           goto Done;
    483         }
    484       } else if (ShellCommandLineGetFlag (Package, L"-pci")) {
    485         AccessType = ShellMmPci;
    486         if (ShellCommandLineGetFlag (Package, L"-pcie")
    487             ) {
    488           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mm");
    489           ShellStatus = SHELL_INVALID_PARAMETER;
    490           goto Done;
    491         }
    492       } else if (ShellCommandLineGetFlag (Package, L"-pcie")) {
    493         AccessType = ShellMmPciExpress;
    494       }
    495     }
    496 
    497     //
    498     // Non interactive for a script file or for the specific parameter
    499     //
    500     Interactive = TRUE;
    501     if (gEfiShellProtocol->BatchIsActive () || ShellCommandLineGetFlag (Package, L"-n")) {
    502       Interactive = FALSE;
    503     }
    504 
    505     Temp = ShellCommandLineGetValue (Package, L"-w");
    506     if (Temp != NULL) {
    507       Size = ShellStrToUintn (Temp);
    508     }
    509     if ((Size != 1) && (Size != 2) && (Size != 4) && (Size != 8)) {
    510       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellDebug1HiiHandle, L"mm", Temp, L"-w");
    511       ShellStatus = SHELL_INVALID_PARAMETER;
    512       goto Done;
    513     }
    514 
    515     Temp = ShellCommandLineGetRawValue (Package, 1);
    516     Status = ShellConvertStringToUint64 (Temp, &Address, TRUE, FALSE);
    517     if (EFI_ERROR (Status)) {
    518       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"mm", Temp);
    519       ShellStatus = SHELL_INVALID_PARAMETER;
    520       goto Done;
    521     }
    522 
    523     if ((Address & (Size - 1)) != 0) {
    524       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_NOT_ALIGNED), gShellDebug1HiiHandle, L"mm", Address);
    525       ShellStatus = SHELL_INVALID_PARAMETER;
    526       goto Done;
    527     }
    528 
    529     if ((AccessType == ShellMmIo) && (Address + Size > MAX_UINT16 + 1)) {
    530       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_IO_ADDRESS_RANGE), gShellDebug1HiiHandle, L"mm");
    531       ShellStatus = SHELL_INVALID_PARAMETER;
    532       goto Done;
    533     }
    534 
    535     //
    536     // locate IO protocol interface
    537     //
    538     HasPciRootBridgeIo = ShellMmLocateIoProtocol (AccessType, Address, &CpuIo, &PciRootBridgeIo);
    539     if ((AccessType == ShellMmPci) || (AccessType == ShellMmPciExpress)) {
    540       if (!HasPciRootBridgeIo) {
    541         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PCIRBIO_NF), gShellDebug1HiiHandle, L"mm");
    542         ShellStatus = SHELL_NOT_FOUND;
    543         goto Done;
    544       }
    545       if (PciRootBridgeIo == NULL) {
    546         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_PCIE_ADDRESS_RANGE), gShellDebug1HiiHandle, L"mm", Address);
    547         ShellStatus = SHELL_INVALID_PARAMETER;
    548         goto Done;
    549       }
    550     }
    551 
    552     //
    553     // Mode 1: Directly set a value
    554     //
    555     Temp = ShellCommandLineGetRawValue (Package, 2);
    556     if (Temp != NULL) {
    557       Status = ShellConvertStringToUint64 (Temp, &Value, TRUE, FALSE);
    558       if (EFI_ERROR (Status)) {
    559         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"mm", Temp);
    560         ShellStatus = SHELL_INVALID_PARAMETER;
    561         goto Done;
    562       }
    563 
    564       if (Value > mShellMmMaxNumber[Size]) {
    565         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"mm", Temp);
    566         ShellStatus = SHELL_INVALID_PARAMETER;
    567         goto Done;
    568       }
    569 
    570       ShellMmAccess (AccessType, PciRootBridgeIo, CpuIo, FALSE, Address, Size, &Value);
    571       goto Done;
    572     }
    573 
    574     //
    575     // Mode 2: Directly show a value
    576     //
    577     if (!Interactive) {
    578       if (!gEfiShellProtocol->BatchIsActive ()) {
    579         ShellPrintHiiEx (-1, -1, NULL, mShellMmAccessTypeStr[AccessType], gShellDebug1HiiHandle);
    580       }
    581       ShellMmAccess (AccessType, PciRootBridgeIo, CpuIo, TRUE, Address, Size, &Buffer);
    582 
    583       if (!gEfiShellProtocol->BatchIsActive ()) {
    584         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_ADDRESS), gShellDebug1HiiHandle, Address);
    585       }
    586       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_BUF), gShellDebug1HiiHandle, Size * 2, Buffer & mShellMmMaxNumber[Size]);
    587       ShellPrintEx (-1, -1, L"\r\n");
    588       goto Done;
    589     }
    590 
    591     //
    592     // Mode 3: Show or set values in interactive mode
    593     //
    594     Complete = FALSE;
    595     do {
    596       if ((AccessType == ShellMmIo) && (Address + Size > MAX_UINT16 + 1)) {
    597         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_ADDRESS_RANGE2), gShellDebug1HiiHandle, L"mm");
    598         break;
    599       }
    600 
    601       ShellMmAccess (AccessType, PciRootBridgeIo, CpuIo, TRUE, Address, Size, &Buffer);
    602       ShellPrintHiiEx (-1, -1, NULL, mShellMmAccessTypeStr[AccessType], gShellDebug1HiiHandle);
    603       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_ADDRESS), gShellDebug1HiiHandle, Address);
    604       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_BUF), gShellDebug1HiiHandle, Size * 2, Buffer & mShellMmMaxNumber[Size]);
    605       ShellPrintEx (-1, -1, L" > ");
    606       //
    607       // wait user input to modify
    608       //
    609       if (InputStr != NULL) {
    610         FreePool (InputStr);
    611         InputStr = NULL;
    612       }
    613       ShellPromptForResponse (ShellPromptResponseTypeFreeform, NULL, (VOID**) &InputStr);
    614 
    615       if (InputStr != NULL) {
    616         //
    617         // skip space characters
    618         //
    619         for (Index = 0; InputStr[Index] == ' '; Index++);
    620 
    621         if (InputStr[Index] != CHAR_NULL) {
    622           if ((InputStr[Index] == '.') || (InputStr[Index] == 'q') || (InputStr[Index] == 'Q')) {
    623             Complete = TRUE;
    624           } else if (!EFI_ERROR (ShellConvertStringToUint64 (InputStr + Index, &Buffer, TRUE, TRUE)) &&
    625                      (Buffer <= mShellMmMaxNumber[Size])
    626                      ) {
    627             ShellMmAccess (AccessType, PciRootBridgeIo, CpuIo, FALSE, Address, Size, &Buffer);
    628           } else {
    629             ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_ERROR), gShellDebug1HiiHandle, L"mm");
    630             continue;
    631           }
    632         }
    633       }
    634 
    635       Address += Size;
    636       ShellPrintEx (-1, -1, L"\r\n");
    637     } while (!Complete);
    638   }
    639   ASSERT (ShellStatus == SHELL_SUCCESS);
    640 
    641 Done:
    642   if (InputStr != NULL) {
    643     FreePool (InputStr);
    644   }
    645   if (Package != NULL) {
    646     ShellCommandLineFreeVarList (Package);
    647   }
    648   return ShellStatus;
    649 }
    650