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