You've already forked slimbootloader
mirror of
https://github.com/Dasharo/slimbootloader.git
synced 2026-03-06 15:26:20 -08:00
63ba5a4912
The 'mm' (formely 'mem') command is being updated to handle PCI device formatted addresses and also to support IO device interfacing. Removing the 'io' command too since it has been intergrated into the 'mm' command. Signed-off-by: James Gutbub <james.gutbub@intel.com>
277 lines
6.7 KiB
C
277 lines
6.7 KiB
C
/** @file
|
|
Shell command `mm` to read/write system memory, PCI config space
|
|
and IO ports.
|
|
|
|
Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include <Library/ShellLib.h>
|
|
#include <Library/PciExpressLib.h>
|
|
#include <Library/IoLib.h>
|
|
|
|
/**
|
|
Read or write memory, PCI config space, or IO ports.
|
|
|
|
@param[in] Shell shell instance
|
|
@param[in] Argc number of command line arguments
|
|
@param[in] Argv command line arguments
|
|
|
|
@retval EFI_SUCCESS
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
ShellCommandMmFunc (
|
|
IN SHELL *Shell,
|
|
IN UINTN Argc,
|
|
IN CHAR16 *Argv[]
|
|
);
|
|
|
|
CONST SHELL_COMMAND ShellCommandMm = {
|
|
L"mm",
|
|
L"Read or write memory, PCI config space, or IO ports",
|
|
&ShellCommandMmFunc
|
|
};
|
|
|
|
/**
|
|
Write memory address given from mm command.
|
|
|
|
@param[in] Addr Starting address to write to
|
|
@param[in] Width Width of the value to write
|
|
@param[in] Value Value to write to the memory address
|
|
@param[in] Count Number of times past the start to write
|
|
@param[in] IsIoAddr If the address given is an IO address
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
MmWrite (
|
|
IN UINTN Addr,
|
|
IN UINTN Width,
|
|
IN UINT64 Value,
|
|
IN UINT32 Count,
|
|
IN BOOLEAN IsIoAddr
|
|
)
|
|
{
|
|
UINTN Index;
|
|
|
|
for (Index = 0; Index < Count; Index++, Addr+=Width) {
|
|
switch (Width) {
|
|
case 1:
|
|
if (IsIoAddr) {
|
|
IoWrite8 (Addr, (UINT8)Value);
|
|
} else {
|
|
MmioWrite8 (Addr, (UINT8)Value);
|
|
}
|
|
break;
|
|
case 2:
|
|
if (IsIoAddr) {
|
|
IoWrite16 (Addr, (UINT16)Value);
|
|
} else {
|
|
MmioWrite16 (Addr, (UINT16)Value);
|
|
}
|
|
break;
|
|
case 4:
|
|
if (IsIoAddr) {
|
|
IoWrite32 (Addr, (UINT32)Value);
|
|
} else {
|
|
MmioWrite32 (Addr, (UINT32)Value);
|
|
}
|
|
break;
|
|
case 8:
|
|
if (IsIoAddr) {
|
|
IoWrite64 (Addr, (UINT64)Value);
|
|
} else {
|
|
MmioWrite64 (Addr, (UINT64)Value);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Read memory address given from mm command.
|
|
|
|
@param[in] Addr Starting address to read from
|
|
@param[in] Width Width of the value to read
|
|
@param[in] Count Number of times past the start to read
|
|
@param[in] IsIoAddr If the address given is an IO address
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
MmRead (
|
|
IN UINTN Addr,
|
|
IN UINTN Width,
|
|
IN UINT32 Count,
|
|
IN BOOLEAN IsIoAddr
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UINT32 Start;
|
|
UINT32 ItemsPerRow;
|
|
|
|
// Pad backward to 16-byte boundary
|
|
ItemsPerRow = 16 / Width;
|
|
Start = (Addr & 0xF) / Width;
|
|
Count += Start;
|
|
|
|
if (Start > 0) {
|
|
ShellPrint (L"%08X: ", Addr & ~0xF);
|
|
for (Index = 0; Index < Start * (Width * 2 + 1); Index++) {
|
|
ShellPrint (L" ");
|
|
}
|
|
}
|
|
|
|
for (Index = Start; Index < Count; Index++, Addr+=Width) {
|
|
if ((Index % ItemsPerRow) == 0) {
|
|
ShellPrint (L"%08X: ", Addr);
|
|
}
|
|
switch (Width) {
|
|
case 1:
|
|
ShellPrint (L"%02X ", IsIoAddr ? IoRead8 (Addr) : MmioRead8 (Addr));
|
|
break;
|
|
case 2:
|
|
ShellPrint (L"%04X ", IsIoAddr ? IoRead16 (Addr) : MmioRead16 (Addr));
|
|
break;
|
|
case 4:
|
|
ShellPrint (L"%08X ", IsIoAddr ? IoRead32 (Addr) : MmioRead32 (Addr));
|
|
break;
|
|
case 8:
|
|
ShellPrint (L"%016llX ", IsIoAddr ? IoRead64 (Addr) : MmioRead64 (Addr));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if ((Index % ItemsPerRow) == (ItemsPerRow - 1)) {
|
|
ShellPrint (L"\n");
|
|
}
|
|
}
|
|
|
|
if ((Index % ItemsPerRow) != 0) {
|
|
ShellPrint (L"\n");
|
|
}
|
|
}
|
|
|
|
/**
|
|
Read or write system memory.
|
|
|
|
@param[in] Shell Shell instance
|
|
@param[in] Argc Number of command line arguments
|
|
@param[in] Argv Command line arguments
|
|
|
|
@retval EFI_SUCCESS
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
ShellCommandMmFunc (
|
|
IN SHELL *Shell,
|
|
IN UINTN Argc,
|
|
IN CHAR16 *Argv[]
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Addr;
|
|
UINTN Index;
|
|
UINTN Width;
|
|
UINT64 Value;
|
|
UINT32 Count;
|
|
BOOLEAN Write;
|
|
BOOLEAN IsPciAddr;
|
|
BOOLEAN IsIoAddr;
|
|
|
|
Status = EFI_SUCCESS;
|
|
IsPciAddr = FALSE;
|
|
IsIoAddr = FALSE;
|
|
Write = FALSE;
|
|
Width = 4;
|
|
Value = 0;
|
|
Count = 1;
|
|
|
|
if ((Argc > 1) && (Argc < 9)) {
|
|
Addr = StrHexToUintn (Argv[1]);
|
|
//
|
|
// Parse optional arguments
|
|
//
|
|
for (Index = 2; Index < Argc; Index++) {
|
|
if (StrCmp (Argv[Index], L"-w") == 0) {
|
|
if ((Index + 1) < Argc) {
|
|
Width = StrHexToUintn (Argv[Index+1]);
|
|
Index++;
|
|
} else {
|
|
ShellPrint (L"Error, '-w' requires [1|2|4|8]\n");
|
|
}
|
|
} else if (StrCmp (Argv[Index], L"-c") == 0) {
|
|
if ((Index + 1) < Argc) {
|
|
Count = StrHexToUintn (Argv[Index+1]);
|
|
Index++;
|
|
} else {
|
|
ShellPrint (L"Error, '-c' requires a value\n");
|
|
}
|
|
} else if (StrCmp (Argv[Index], L"-pci") == 0) {
|
|
IsPciAddr = TRUE;
|
|
} else if (StrCmp (Argv[Index], L"-io") == 0) {
|
|
IsIoAddr = TRUE;
|
|
} else if (!Write) {
|
|
Value = StrHexToUintn (Argv[Index]);
|
|
Write = TRUE;
|
|
} else {
|
|
ShellPrint (L"Invalid parameter '%s'", Argv[Index]);
|
|
Status = EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
} else if (Argc >= 9) {
|
|
ShellPrint (L"Error, too many arguments\n");
|
|
Status = EFI_INVALID_PARAMETER;
|
|
} else {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
if ((Width != 1) && (Width != 2) && (Width != 4) && (Width != 8)) {
|
|
ShellPrint (L"Error, width %u not supported\n", Width);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
// Make sure access is aligned
|
|
if ((Addr & (Width - 1)) != 0) {
|
|
ShellPrint (L"Error, unaligned access\n");
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (IsIoAddr && IsPciAddr) {
|
|
ShellPrint (L"Error, cannot be both -pci & -io\n");
|
|
return EFI_INVALID_PARAMETER;
|
|
} else if (IsPciAddr) {
|
|
Addr = (UINTN) (PcdGet64 (PcdPciExpressBaseAddress) +
|
|
PCI_EXPRESS_LIB_ADDRESS ((Addr >> 24) & 0xFF, (Addr >> 16) & 0xFF, (Addr >> 8) & 0xFF, Addr & 0xFF));
|
|
}
|
|
|
|
if (Write) {
|
|
MmWrite (Addr, Width, Value, Count, IsIoAddr);
|
|
} else {
|
|
MmRead (Addr, Width, Count, IsIoAddr);
|
|
}
|
|
}
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
ShellPrint (L"Usage: %s <addr> [value] [-w <1|2|4|8>] [-c count] [-io | -pci] \n", Argv[0]);
|
|
ShellPrint (L" defaults: -w=4 -c=1\n");
|
|
ShellPrint (L" examples:\n");
|
|
ShellPrint (L" # Read 1 dword at the address\n");
|
|
ShellPrint (L" mm c0000000\n");
|
|
ShellPrint (L" # Read PCI config space for 0.2:0[0]\n");
|
|
ShellPrint (L" mm 00020000 -w 1 -c 100 -pci\n");
|
|
ShellPrint (L" # Write 256 dwords of 0 starting at address\n");
|
|
ShellPrint (L" mm c0000000 0 -w 4 -c 100\n");
|
|
ShellPrint (L" # Read 1 byte from IO port 80h\n");
|
|
ShellPrint (L" mm 80 -w 1 -io\n");
|
|
}
|
|
|
|
return Status;
|
|
}
|