Mm.c revision 304316f430519b5a84cf7402d1721d22ba6f94b7
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
22typedef enum {
23  ShellMmMemory,
24  ShellMmMemoryMappedIo,
25  ShellMmIo,
26  ShellMmPci,
27  ShellMmPciExpress
28} SHELL_MM_ACCESS_TYPE;
29
30CONST 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
38STATIC 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
49CONST UINT64 mShellMmMaxNumber[] = {
50  0, MAX_UINT8, MAX_UINT16, 0, MAX_UINT32, 0, 0, 0, MAX_UINT64
51};
52CONST EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH mShellMmRootBridgeIoWidth[] = {
53  0, EfiPciWidthUint8, EfiPciWidthUint16, 0, EfiPciWidthUint32, 0, 0, 0, EfiPciWidthUint64
54};
55CONST 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**/
71VOID
72EFIAPI
73ShellMmDecodePciAddress (
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**/
130VOID
131ShellMmAccess (
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**/
297BOOLEAN
298ShellMmLocateIoProtocol (
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  Status = gBS->LocateHandleBuffer (
321                  ByProtocol,
322                  &gEfiPciRootBridgeIoProtocolGuid,
323                  NULL,
324                  &HandleCount,
325                  &HandleBuffer
326                  );
327  if (EFI_ERROR (Status) || (HandleCount == 0)) {
328    return FALSE;
329  }
330
331  if ((AccessType == ShellMmPci) || (AccessType == ShellMmPciExpress)) {
332    ShellMmDecodePciAddress ((BOOLEAN) (AccessType == ShellMmPci), Address, &Segment, &Bus, NULL, NULL, NULL);
333  }
334
335  //
336  // Find the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL of the specified segment & bus number
337  //
338  for (Index = 0; (Index < HandleCount) && (*PciRootBridgeIo == NULL); Index++) {
339    Status = gBS->HandleProtocol (
340                    HandleBuffer[Index],
341                    &gEfiPciRootBridgeIoProtocolGuid,
342                    (VOID *) &Io
343                    );
344    if (EFI_ERROR (Status)) {
345      continue;
346    }
347
348    if ((((AccessType == ShellMmPci) || (AccessType == ShellMmPciExpress)) && (Io->SegmentNumber == Segment)) ||
349        ((AccessType == ShellMmIo) || (AccessType == ShellMmMemoryMappedIo))
350        ) {
351      Status = Io->Configuration (Io, (VOID **) &Descriptors);
352      if (!EFI_ERROR (Status)) {
353        while (Descriptors->Desc != ACPI_END_TAG_DESCRIPTOR) {
354          //
355          // Compare the segment and bus range for PCI/PCIE access
356          //
357          if ((Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) &&
358              ((AccessType == ShellMmPci) || (AccessType == ShellMmPciExpress)) &&
359              ((Bus >= Descriptors->AddrRangeMin) && (Bus <= Descriptors->AddrRangeMax))
360              ) {
361            *PciRootBridgeIo = Io;
362            break;
363
364          //
365          // Compare the address range for MMIO/IO access
366          //
367          } else if ((((Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_IO) && (AccessType == ShellMmIo)) ||
368                      ((Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) && (AccessType == ShellMmMemoryMappedIo))
369                      ) && ((Address >= Descriptors->AddrRangeMin) && (Address <= Descriptors->AddrRangeMax))
370                     ) {
371            *PciRootBridgeIo = Io;
372            break;
373          }
374          Descriptors++;
375        }
376      }
377    }
378  }
379  if (HandleBuffer != NULL) {
380    FreePool (HandleBuffer);
381  }
382
383  return TRUE;
384}
385
386/**
387  Function for 'mm' command.
388
389  @param[in] ImageHandle  Handle to the Image (NULL if Internal).
390  @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
391**/
392SHELL_STATUS
393EFIAPI
394ShellCommandRunMm (
395  IN EFI_HANDLE        ImageHandle,
396  IN EFI_SYSTEM_TABLE  *SystemTable
397  )
398{
399  EFI_STATUS                            Status;
400  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *PciRootBridgeIo;
401  EFI_CPU_IO2_PROTOCOL                  *CpuIo;
402  UINT64                                Address;
403  UINT64                                Value;
404  SHELL_MM_ACCESS_TYPE                  AccessType;
405  UINT64                                Buffer;
406  UINTN                                 Index;
407  UINTN                                 Size;
408  BOOLEAN                               Complete;
409  CHAR16                                *InputStr;
410  BOOLEAN                               Interactive;
411  LIST_ENTRY                            *Package;
412  CHAR16                                *ProblemParam;
413  SHELL_STATUS                          ShellStatus;
414  CONST CHAR16                          *Temp;
415  BOOLEAN                               HasPciRootBridgeIo;
416
417  Value = 0;
418  Address = 0;
419  ShellStatus = SHELL_SUCCESS;
420  InputStr = NULL;
421  Size = 1;
422  AccessType = ShellMmMemory;
423
424  //
425  // Parse arguments
426  //
427  Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
428  if (EFI_ERROR (Status)) {
429    if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
430      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"mm", ProblemParam);
431      FreePool (ProblemParam);
432      ShellStatus = SHELL_INVALID_PARAMETER;
433      goto Done;
434    } else {
435      ASSERT (FALSE);
436    }
437  } else {
438    if (ShellCommandLineGetCount (Package) < 2) {
439      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"mm");
440      ShellStatus = SHELL_INVALID_PARAMETER;
441      goto Done;
442    } else if (ShellCommandLineGetCount (Package) > 3) {
443      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mm");
444      ShellStatus = SHELL_INVALID_PARAMETER;
445      goto Done;
446    } else if (ShellCommandLineGetFlag (Package, L"-w") && ShellCommandLineGetValue (Package, L"-w") == NULL) {
447      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDebug1HiiHandle, L"mm", L"-w");
448      ShellStatus = SHELL_INVALID_PARAMETER;
449      goto Done;
450    } else {
451      if (ShellCommandLineGetFlag (Package, L"-mmio")) {
452        AccessType = ShellMmMemoryMappedIo;
453        if (ShellCommandLineGetFlag (Package, L"-mem")
454            || ShellCommandLineGetFlag (Package, L"-io")
455            || ShellCommandLineGetFlag (Package, L"-pci")
456            || ShellCommandLineGetFlag (Package, L"-pcie")
457            ) {
458          ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mm");
459          ShellStatus = SHELL_INVALID_PARAMETER;
460          goto Done;
461        }
462      } else if (ShellCommandLineGetFlag (Package, L"-mem")) {
463        AccessType = ShellMmMemory;
464        if (ShellCommandLineGetFlag (Package, L"-io")
465            || ShellCommandLineGetFlag (Package, L"-pci")
466            || ShellCommandLineGetFlag (Package, L"-pcie")
467            ) {
468          ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mm");
469          ShellStatus = SHELL_INVALID_PARAMETER;
470          goto Done;
471        }
472      } else if (ShellCommandLineGetFlag (Package, L"-io")) {
473        AccessType = ShellMmIo;
474        if (ShellCommandLineGetFlag (Package, L"-pci")
475            || ShellCommandLineGetFlag (Package, L"-pcie")
476            ) {
477          ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mm");
478          ShellStatus = SHELL_INVALID_PARAMETER;
479          goto Done;
480        }
481      } else if (ShellCommandLineGetFlag (Package, L"-pci")) {
482        AccessType = ShellMmPci;
483        if (ShellCommandLineGetFlag (Package, L"-pcie")
484            ) {
485          ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"mm");
486          ShellStatus = SHELL_INVALID_PARAMETER;
487          goto Done;
488        }
489      } else if (ShellCommandLineGetFlag (Package, L"-pcie")) {
490        AccessType = ShellMmPciExpress;
491      }
492    }
493
494    //
495    // Non interactive for a script file or for the specific parameter
496    //
497    Interactive = TRUE;
498    if (gEfiShellProtocol->BatchIsActive () || ShellCommandLineGetFlag (Package, L"-n")) {
499      Interactive = FALSE;
500    }
501
502    Temp = ShellCommandLineGetValue (Package, L"-w");
503    if (Temp != NULL) {
504      Size = ShellStrToUintn (Temp);
505    }
506    if ((Size != 1) && (Size != 2) && (Size != 4) && (Size != 8)) {
507      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellDebug1HiiHandle, L"mm", Temp, L"-w");
508      ShellStatus = SHELL_INVALID_PARAMETER;
509      goto Done;
510    }
511
512    Temp = ShellCommandLineGetRawValue (Package, 1);
513    Status = ShellConvertStringToUint64 (Temp, &Address, TRUE, FALSE);
514    if (EFI_ERROR (Status)) {
515      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"mm", Temp);
516      ShellStatus = SHELL_INVALID_PARAMETER;
517      goto Done;
518    }
519
520    if ((Address & (Size - 1)) != 0) {
521      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_NOT_ALIGNED), gShellDebug1HiiHandle, L"mm", Address);
522      ShellStatus = SHELL_INVALID_PARAMETER;
523      goto Done;
524    }
525
526    if ((AccessType == ShellMmIo) && (Address + Size > MAX_UINT16 + 1)) {
527      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_IO_ADDRESS_RANGE), gShellDebug1HiiHandle, L"mm");
528      ShellStatus = SHELL_INVALID_PARAMETER;
529      goto Done;
530    }
531
532    //
533    // locate IO protocol interface
534    //
535    HasPciRootBridgeIo = ShellMmLocateIoProtocol (AccessType, Address, &CpuIo, &PciRootBridgeIo);
536    if ((AccessType == ShellMmPci) || (AccessType == ShellMmPciExpress)) {
537      if (!HasPciRootBridgeIo) {
538        ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PCIRBIO_NF), gShellDebug1HiiHandle, L"mm");
539        ShellStatus = SHELL_NOT_FOUND;
540        goto Done;
541      }
542      if (PciRootBridgeIo == NULL) {
543        ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_PCIE_ADDRESS_RANGE), gShellDebug1HiiHandle, L"mm", Address);
544        ShellStatus = SHELL_INVALID_PARAMETER;
545        goto Done;
546      }
547    }
548
549    //
550    // Mode 1: Directly set a value
551    //
552    Temp = ShellCommandLineGetRawValue (Package, 2);
553    if (Temp != NULL) {
554      Status = ShellConvertStringToUint64 (Temp, &Value, TRUE, FALSE);
555      if (EFI_ERROR (Status)) {
556        ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"mm", Temp);
557        ShellStatus = SHELL_INVALID_PARAMETER;
558        goto Done;
559      }
560
561      if (Value > mShellMmMaxNumber[Size]) {
562        ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"mm", Temp);
563        ShellStatus = SHELL_INVALID_PARAMETER;
564        goto Done;
565      }
566
567      ShellMmAccess (AccessType, PciRootBridgeIo, CpuIo, FALSE, Address, Size, &Value);
568      goto Done;
569    }
570
571    //
572    // Mode 2: Directly show a value
573    //
574    if (!Interactive) {
575      if (!gEfiShellProtocol->BatchIsActive ()) {
576        ShellPrintHiiEx (-1, -1, NULL, mShellMmAccessTypeStr[AccessType], gShellDebug1HiiHandle);
577      }
578      ShellMmAccess (AccessType, PciRootBridgeIo, CpuIo, TRUE, Address, Size, &Buffer);
579
580      if (!gEfiShellProtocol->BatchIsActive ()) {
581        ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_ADDRESS), gShellDebug1HiiHandle, Address);
582      }
583      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_BUF), gShellDebug1HiiHandle, Size * 2, Buffer & mShellMmMaxNumber[Size]);
584      ShellPrintEx (-1, -1, L"\r\n");
585      goto Done;
586    }
587
588    //
589    // Mode 3: Show or set values in interactive mode
590    //
591    Complete = FALSE;
592    do {
593      if ((AccessType == ShellMmIo) && (Address + Size > MAX_UINT16 + 1)) {
594        ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_ADDRESS_RANGE2), gShellDebug1HiiHandle, L"mm");
595        break;
596      }
597
598      ShellMmAccess (AccessType, PciRootBridgeIo, CpuIo, TRUE, Address, Size, &Buffer);
599      ShellPrintHiiEx (-1, -1, NULL, mShellMmAccessTypeStr[AccessType], gShellDebug1HiiHandle);
600      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_ADDRESS), gShellDebug1HiiHandle, Address);
601      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_BUF), gShellDebug1HiiHandle, Size * 2, Buffer & mShellMmMaxNumber[Size]);
602      ShellPrintEx (-1, -1, L" > ");
603      //
604      // wait user input to modify
605      //
606      if (InputStr != NULL) {
607        FreePool (InputStr);
608        InputStr = NULL;
609      }
610      ShellPromptForResponse (ShellPromptResponseTypeFreeform, NULL, (VOID**) &InputStr);
611
612      if (InputStr != NULL) {
613        //
614        // skip space characters
615        //
616        for (Index = 0; InputStr[Index] == ' '; Index++);
617      }
618
619      if ((InputStr != NULL) && (InputStr[Index] != CHAR_NULL)) {
620        if ((InputStr[Index] == '.') || (InputStr[Index] == 'q') || (InputStr[Index] == 'Q')) {
621          Complete = TRUE;
622        } else if (!EFI_ERROR (ShellConvertStringToUint64 (InputStr + Index, &Buffer, TRUE, TRUE)) &&
623                   (Buffer <= mShellMmMaxNumber[Size])
624                   ) {
625          ShellMmAccess (AccessType, PciRootBridgeIo, CpuIo, FALSE, Address, Size, &Buffer);
626        } else {
627          ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MM_ERROR), gShellDebug1HiiHandle, L"mm");
628          continue;
629        }
630      }
631
632      Address += Size;
633      ShellPrintEx (-1, -1, L"\r\n");
634    } while (!Complete);
635  }
636  ASSERT (ShellStatus == SHELL_SUCCESS);
637
638Done:
639  if (InputStr != NULL) {
640    FreePool (InputStr);
641  }
642  if (Package != NULL) {
643    ShellCommandLineFreeVarList (Package);
644  }
645  return ShellStatus;
646}
647