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
ShellMmDecodePciAddress(IN BOOLEAN PciFormat,IN UINT64 Address,OUT UINT32 * Segment,OUT UINT8 * Bus,OUT UINT8 * Device,OPTIONAL OUT UINT8 * Function,OPTIONAL OUT UINT32 * Register OPTIONAL)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
ShellMmAccess(IN SHELL_MM_ACCESS_TYPE AccessType,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * PciRootBridgeIo,IN EFI_CPU_IO2_PROTOCOL * CpuIo,IN BOOLEAN Read,IN UINT64 Address,IN UINTN Size,IN OUT VOID * Buffer)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
ShellMmLocateIoProtocol(IN SHELL_MM_ACCESS_TYPE AccessType,IN UINT64 Address,OUT EFI_CPU_IO2_PROTOCOL ** CpuIo,OUT EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL ** PciRootBridgeIo)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
ShellCommandRunMm(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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