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
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)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
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)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
ShellMmLocateIoProtocol(IN SHELL_MM_ACCESS_TYPE AccessType,IN UINT64 Address,OUT EFI_CPU_IO2_PROTOCOL ** CpuIo,OUT EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL ** PciRootBridgeIo)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
ShellCommandRunMm(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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