From 1d5d0ae92d95410f20bc6daab7a47e129fb2547a Mon Sep 17 00:00:00 2001 From: andrewfish Date: Tue, 1 Feb 2011 05:41:42 +0000 Subject: Add ArmPlatformPkg from ARM Ltd. patch. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11291 6f19259b-4bc3-4df7-8a09-765794883524 --- ArmPlatformPkg/Library/EblCmdLib/EblCmdLib.c | 386 +++++++++++++++++++++++++ ArmPlatformPkg/Library/EblCmdLib/EblCmdLib.inf | 53 ++++ ArmPlatformPkg/Library/EblCmdLib/EblCmdMmu.c | 354 +++++++++++++++++++++++ 3 files changed, 793 insertions(+) create mode 100644 ArmPlatformPkg/Library/EblCmdLib/EblCmdLib.c create mode 100644 ArmPlatformPkg/Library/EblCmdLib/EblCmdLib.inf create mode 100644 ArmPlatformPkg/Library/EblCmdLib/EblCmdMmu.c (limited to 'ArmPlatformPkg/Library/EblCmdLib') diff --git a/ArmPlatformPkg/Library/EblCmdLib/EblCmdLib.c b/ArmPlatformPkg/Library/EblCmdLib/EblCmdLib.c new file mode 100644 index 0000000000..9289444756 --- /dev/null +++ b/ArmPlatformPkg/Library/EblCmdLib/EblCmdLib.c @@ -0,0 +1,386 @@ +/** @file +* +* Copyright (c) 2011, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +EFI_STATUS +EblDumpMmu ( + IN UINTN Argc, + IN CHAR8 **Argv + ); + +/** + Simple arm disassembler via a library + + Argv[0] - symboltable + Argv[1] - Optional qoted format string + Argv[2] - Optional flag + + @param Argc Number of command arguments in Argv + @param Argv Array of strings that represent the parsed command line. + Argv[0] is the comamnd name + + @return EFI_SUCCESS + +**/ +EFI_STATUS +EblSymbolTable ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + EFI_STATUS Status; + EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *DebugImageTableHeader = NULL; + EFI_DEBUG_IMAGE_INFO *DebugTable; + UINTN Entry; + CHAR8 *Format; + CHAR8 *Pdb; + UINT32 PeCoffSizeOfHeaders; + UINT32 ImageBase; + BOOLEAN Elf; + + // Need to add lots of error checking on the passed in string + // Default string is for RealView debugger + Format = (Argc > 1) ? Argv[1] : "load /a /ni /np %a &0x%x"; + Elf = (Argc > 2) ? FALSE : TRUE; + + Status = EfiGetSystemConfigurationTable (&gEfiDebugImageInfoTableGuid, (VOID **)&DebugImageTableHeader); + if (EFI_ERROR (Status)) { + return Status; + } + + DebugTable = DebugImageTableHeader->EfiDebugImageInfoTable; + if (DebugTable == NULL) { + return EFI_SUCCESS; + } + + for (Entry = 0; Entry < DebugImageTableHeader->TableSize; Entry++, DebugTable++) { + if (DebugTable->NormalImage != NULL) { + if ((DebugTable->NormalImage->ImageInfoType == EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL) && (DebugTable->NormalImage->LoadedImageProtocolInstance != NULL)) { + ImageBase = (UINT32)DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase; + PeCoffSizeOfHeaders = PeCoffGetSizeOfHeaders ((VOID *)(UINTN)ImageBase); + Pdb = PeCoffLoaderGetPdbPointer (DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase); + if (Pdb != NULL) { + if (Elf) { + // ELF and Mach-O images don't include the header so the linked address does not include header + ImageBase += PeCoffSizeOfHeaders; + } + AsciiPrint (Format, Pdb, ImageBase); + AsciiPrint ("\n"); + } else { + } + } + } + } + + return EFI_SUCCESS; +} + + +/** + Simple arm disassembler via a library + + Argv[0] - disasm + Argv[1] - Address to start disassembling from + ARgv[2] - Number of instructions to disassembly (optional) + + @param Argc Number of command arguments in Argv + @param Argv Array of strings that represent the parsed command line. + Argv[0] is the comamnd name + + @return EFI_SUCCESS + +**/ +EFI_STATUS +EblDisassembler ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + UINT8 *Ptr, *CurrentAddress; + UINT32 Address; + UINT32 Count; + CHAR8 Buffer[80]; + UINT32 ItBlock; + + if (Argc < 2) { + return EFI_INVALID_PARAMETER; + } + + Address = AsciiStrHexToUintn (Argv[1]); + Count = (Argc > 2) ? (UINT32)AsciiStrHexToUintn (Argv[2]) : 20; + + Ptr = (UINT8 *)(UINTN)Address; + ItBlock = 0; + do { + CurrentAddress = Ptr; + DisassembleInstruction (&Ptr, TRUE, TRUE, &ItBlock, Buffer, sizeof (Buffer)); + AsciiPrint ("0x%08x: %a\n", CurrentAddress, Buffer); + } while (Count-- > 0); + + + return EFI_SUCCESS; +} + + +CHAR8 * +ImageHandleToPdbFileName ( + IN EFI_HANDLE Handle + ) +{ + EFI_STATUS Status; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + CHAR8 *Pdb; + CHAR8 *StripLeading; + + Status = gBS->HandleProtocol (Handle, &gEfiLoadedImageProtocolGuid, (VOID **)&LoadedImage); + if (EFI_ERROR (Status)) { + return ""; + } + + Pdb = PeCoffLoaderGetPdbPointer (LoadedImage->ImageBase); + StripLeading = AsciiStrStr (Pdb, "\\ARM\\"); + if (StripLeading == NULL) { + StripLeading = AsciiStrStr (Pdb, "/ARM/"); + if (StripLeading == NULL) { + return Pdb; + } + } + // Hopefully we hacked off the unneeded part + return (StripLeading + 5); +} + + +CHAR8 *mTokenList[] = { + /*"SEC",*/ + "PEI", + "DXE", + /*"BDS",*/ + NULL +}; + +/** + Simple arm disassembler via a library + + Argv[0] - disasm + Argv[1] - Address to start disassembling from + ARgv[2] - Number of instructions to disassembly (optional) + + @param Argc Number of command arguments in Argv + @param Argv Array of strings that represent the parsed command line. + Argv[0] is the comamnd name + + @return EFI_SUCCESS + +**/ +EFI_STATUS +EblPerformance ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + UINTN Key; + CONST VOID *Handle; + CONST CHAR8 *Token, *Module; + UINT64 Start, Stop, TimeStamp; + UINT64 Delta, TicksPerSecond, Milliseconds, Microseconds; + UINTN Index; + + TicksPerSecond = GetPerformanceCounterProperties (NULL, NULL); + + Key = 0; + do { + Key = GetPerformanceMeasurement (Key, (CONST VOID **)&Handle, &Token, &Module, &Start, &Stop); + if (Key != 0) { + if (AsciiStriCmp ("StartImage:", Token) == 0) { + if (Stop == 0) { + // The entry for EBL is still running so the stop time will be zero. Skip it + AsciiPrint (" running %a\n", ImageHandleToPdbFileName ((EFI_HANDLE)Handle)); + } else { + Delta = Start - Stop; + Microseconds = DivU64x64Remainder (MultU64x32 (Delta, 1000000), TicksPerSecond, NULL); + AsciiPrint ("%10ld us %a\n", Microseconds, ImageHandleToPdbFileName ((EFI_HANDLE)Handle)); + } + } + } + } while (Key != 0); + + AsciiPrint ("\n"); + + TimeStamp = 0; + Key = 0; + do { + Key = GetPerformanceMeasurement (Key, (CONST VOID **)&Handle, &Token, &Module, &Start, &Stop); + if (Key != 0) { + for (Index = 0; mTokenList[Index] != NULL; Index++) { + if (AsciiStriCmp (mTokenList[Index], Token) == 0) { + Delta = Start - Stop; + TimeStamp += Delta; + Milliseconds = DivU64x64Remainder (MultU64x32 (Delta, 1000), TicksPerSecond, NULL); + AsciiPrint ("%6a %6ld ms\n", Token, Milliseconds); + break; + } + } + } + } while (Key != 0); + + AsciiPrint ("Total Time = %ld ms\n\n", DivU64x64Remainder (MultU64x32 (TimeStamp, 1000), TicksPerSecond, NULL)); + + return EFI_SUCCESS; +} + +#define EFI_MEMORY_PORT_IO 0x4000000000000000ULL + +EFI_STATUS +EblDumpGcd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + EFI_STATUS Status; + UINTN NumberOfDescriptors; + UINTN i; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap; + EFI_GCD_IO_SPACE_DESCRIPTOR *IoSpaceMap; + + Status = gDS->GetMemorySpaceMap(&NumberOfDescriptors,&MemorySpaceMap); + if (EFI_ERROR (Status)) { + return Status; + } + AsciiPrint (" Address Range Image Device Attributes\n"); + AsciiPrint ("__________________________________________________________\n"); + for (i=0; i < NumberOfDescriptors; i++) { + //AsciiPrint ("%016lx - %016lx",MemorySpaceMap[i].BaseAddress,MemorySpaceMap[i].BaseAddress+MemorySpaceMap[i].Length); + AsciiPrint ("MEM %08lx - %08lx",(UINT64)MemorySpaceMap[i].BaseAddress,MemorySpaceMap[i].BaseAddress+MemorySpaceMap[i].Length-1); + AsciiPrint (" %08x %08x",MemorySpaceMap[i].ImageHandle,MemorySpaceMap[i].DeviceHandle); + + if (MemorySpaceMap[i].Attributes & EFI_MEMORY_RUNTIME) + AsciiPrint (" RUNTIME"); + if (MemorySpaceMap[i].Attributes & EFI_MEMORY_PORT_IO) + AsciiPrint (" PORT_IO"); + + if (MemorySpaceMap[i].Attributes & EFI_MEMORY_UC) + AsciiPrint (" MEM_UC"); + if (MemorySpaceMap[i].Attributes & EFI_MEMORY_WC) + AsciiPrint (" MEM_WC"); + if (MemorySpaceMap[i].Attributes & EFI_MEMORY_WT) + AsciiPrint (" MEM_WT"); + if (MemorySpaceMap[i].Attributes & EFI_MEMORY_WB) + AsciiPrint (" MEM_WB"); + if (MemorySpaceMap[i].Attributes & EFI_MEMORY_UCE) + AsciiPrint (" MEM_UCE"); + if (MemorySpaceMap[i].Attributes & EFI_MEMORY_WP) + AsciiPrint (" MEM_WP"); + if (MemorySpaceMap[i].Attributes & EFI_MEMORY_RP) + AsciiPrint (" MEM_RP"); + if (MemorySpaceMap[i].Attributes & EFI_MEMORY_XP) + AsciiPrint (" MEM_XP"); + + if (MemorySpaceMap[i].GcdMemoryType & EfiGcdMemoryTypeNonExistent) + AsciiPrint (" TYPE_NONEXISTENT"); + if (MemorySpaceMap[i].GcdMemoryType & EfiGcdMemoryTypeReserved) + AsciiPrint (" TYPE_RESERVED"); + if (MemorySpaceMap[i].GcdMemoryType & EfiGcdMemoryTypeSystemMemory) + AsciiPrint (" TYPE_SYSMEM"); + if (MemorySpaceMap[i].GcdMemoryType & EfiGcdMemoryTypeMemoryMappedIo) + AsciiPrint (" TYPE_MEMMAP"); + + AsciiPrint ("\n"); + } + + Status = gDS->GetIoSpaceMap(&NumberOfDescriptors,&IoSpaceMap); + if (EFI_ERROR (Status)) { + return Status; + } + for (i=0; i < NumberOfDescriptors; i++) { + AsciiPrint ("IO %08lx - %08lx",IoSpaceMap[i].BaseAddress,IoSpaceMap[i].BaseAddress+IoSpaceMap[i].Length); + AsciiPrint ("\t%08x %08x",IoSpaceMap[i].ImageHandle,IoSpaceMap[i].DeviceHandle); + + if (IoSpaceMap[i].GcdIoType & EfiGcdMemoryTypeNonExistent) + AsciiPrint (" TYPE_NONEXISTENT"); + if (IoSpaceMap[i].GcdIoType & EfiGcdMemoryTypeReserved) + AsciiPrint (" TYPE_RESERVED"); + if (IoSpaceMap[i].GcdIoType & EfiGcdIoTypeIo) + AsciiPrint (" TYPE_IO"); + + AsciiPrint ("\n"); + } + + return EFI_SUCCESS; +} + +GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mLibCmdTemplate[] = +{ + { + "disasm address [count]", + " disassemble count instructions", + NULL, + EblDisassembler + }, + { + "performance", + " Display boot performance info", + NULL, + EblPerformance + }, + { + "symboltable [\"format string\"] [PECOFF]", + " show symbol table commands for debugger", + NULL, + EblSymbolTable + }, + { + "dumpgcd", + " dump Global Coherency Domain", + NULL, + EblDumpGcd + }, + { + "dumpmmu", + " dump MMU Table", + NULL, + EblDumpMmu + } +}; + + +VOID +EblInitializeExternalCmd ( + VOID + ) +{ + EblAddCommands (mLibCmdTemplate, sizeof (mLibCmdTemplate)/sizeof (EBL_COMMAND_TABLE)); + return; +} diff --git a/ArmPlatformPkg/Library/EblCmdLib/EblCmdLib.inf b/ArmPlatformPkg/Library/EblCmdLib/EblCmdLib.inf new file mode 100644 index 0000000000..fd327cd4a1 --- /dev/null +++ b/ArmPlatformPkg/Library/EblCmdLib/EblCmdLib.inf @@ -0,0 +1,53 @@ +#/** @file +# +# Copyright (c) 2010, ARM Ltd. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = ArmVeEblCmdLib + FILE_GUID = 6085e1ca-0d2d-4ba4-9872-c59b36ffd6ad + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = EblCmdLib|DXE_DRIVER UEFI_APPLICATION UEFI_DRIVER + + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources.common] + EblCmdLib.c + EblCmdMmu.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + ArmPkg/ArmPkg.dec + +[LibraryClasses] + BaseLib + ArmLib + DebugLib + ArmDisassemblerLib + PerformanceLib + TimerLib + +[Protocols] + gEfiDebugSupportProtocolGuid + gEfiLoadedImageProtocolGuid + +[Guids] + gEfiDebugImageInfoTableGuid diff --git a/ArmPlatformPkg/Library/EblCmdLib/EblCmdMmu.c b/ArmPlatformPkg/Library/EblCmdLib/EblCmdMmu.c new file mode 100644 index 0000000000..fdbdd906db --- /dev/null +++ b/ArmPlatformPkg/Library/EblCmdLib/EblCmdMmu.c @@ -0,0 +1,354 @@ +/** @file +* +* Copyright (c) 2011, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define GET_TT_ATTRIBUTES(TTEntry) ((TTEntry) & ~(TT_DESCRIPTOR_SECTION_BASE_ADDRESS_MASK)) +#define GET_TT_PAGE_ATTRIBUTES(TTEntry) ((TTEntry) & 0xFFF) +#define GET_TT_LARGEPAGE_ATTRIBUTES(TTEntry) ((TTEntry) & 0xFFFF) + +// Section +#define TT_DESCRIPTOR_SECTION_STRONGLY_ORDER (TT_DESCRIPTOR_SECTION_TYPE_SECTION | \ + TT_DESCRIPTOR_SECTION_NS_NON_SECURE | \ + TT_DESCRIPTOR_SECTION_NG_GLOBAL | \ + TT_DESCRIPTOR_SECTION_S_NOT_SHARED | \ + TT_DESCRIPTOR_SECTION_DOMAIN(0) | \ + TT_DESCRIPTOR_SECTION_AP_RW_RW | \ + TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED) + +// Small Page +#define TT_DESCRIPTOR_PAGE_WRITE_BACK (TT_DESCRIPTOR_PAGE_TYPE_PAGE | \ + TT_DESCRIPTOR_PAGE_NG_GLOBAL | \ + TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \ + TT_DESCRIPTOR_PAGE_AP_RW_RW | \ + TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_ALLOC) +#define TT_DESCRIPTOR_PAGE_WRITE_THROUGH (TT_DESCRIPTOR_PAGE_TYPE_PAGE | \ + TT_DESCRIPTOR_PAGE_NG_GLOBAL | \ + TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \ + TT_DESCRIPTOR_PAGE_AP_RW_RW | \ + TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC) +#define TT_DESCRIPTOR_PAGE_DEVICE (TT_DESCRIPTOR_PAGE_TYPE_PAGE | \ + TT_DESCRIPTOR_PAGE_NG_GLOBAL | \ + TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \ + TT_DESCRIPTOR_PAGE_AP_RW_RW | \ + TT_DESCRIPTOR_PAGE_CACHE_POLICY_SHAREABLE_DEVICE) +#define TT_DESCRIPTOR_PAGE_UNCACHED (TT_DESCRIPTOR_PAGE_TYPE_PAGE | \ + TT_DESCRIPTOR_PAGE_NG_GLOBAL | \ + TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \ + TT_DESCRIPTOR_PAGE_AP_RW_RW | \ + TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE) + +#define TT_DESCRIPTOR_PAGE_STRONGLY_ORDER (TT_DESCRIPTOR_PAGE_TYPE_PAGE | \ + TT_DESCRIPTOR_PAGE_NG_GLOBAL | \ + TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \ + TT_DESCRIPTOR_PAGE_AP_RW_RW | \ + TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED) + +// Large Page +#define TT_DESCRIPTOR_LARGEPAGE_WRITE_BACK (TT_DESCRIPTOR_PAGE_TYPE_LARGEPAGE | \ + TT_DESCRIPTOR_PAGE_NG_GLOBAL | \ + TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \ + TT_DESCRIPTOR_PAGE_AP_RW_RW | \ + TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC) +#define TT_DESCRIPTOR_LARGEPAGE_WRITE_THROUGH (TT_DESCRIPTOR_PAGE_TYPE_LARGEPAGE | \ + TT_DESCRIPTOR_PAGE_NG_GLOBAL | \ + TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \ + TT_DESCRIPTOR_PAGE_AP_RW_RW | \ + TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC) +#define TT_DESCRIPTOR_LARGEPAGE_DEVICE (TT_DESCRIPTOR_PAGE_TYPE_LARGEPAGE | \ + TT_DESCRIPTOR_PAGE_NG_GLOBAL | \ + TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \ + TT_DESCRIPTOR_PAGE_AP_RW_RW | \ + TT_DESCRIPTOR_SECTION_CACHE_POLICY_SHAREABLE_DEVICE) +#define TT_DESCRIPTOR_LARGEPAGE_UNCACHED (TT_DESCRIPTOR_PAGE_TYPE_LARGEPAGE | \ + TT_DESCRIPTOR_PAGE_NG_GLOBAL | \ + TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \ + TT_DESCRIPTOR_PAGE_AP_RW_RW | \ + TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE) + + +typedef enum { Level0, Level1,Level2 } MMU_LEVEL; + +typedef struct { + MMU_LEVEL Level; + UINT32 Value; + UINT32 Index; + UINT32* Table; +} MMU_ENTRY; + +MMU_ENTRY MmuEntryCreate(MMU_LEVEL Level,UINT32* Table,UINT32 Index) { + MMU_ENTRY Entry; + Entry.Level = Level; + Entry.Value = Table[Index]; + Entry.Table = Table; + Entry.Index = Index; + return Entry; +} + +UINT32 MmuEntryIsValidAddress(MMU_LEVEL Level, UINT32 Entry) { + if (Level == Level0) { + return 0; + } else if (Level == Level1) { + if ((Entry & 0x3) == 0) { // Ignored + return 0; + } else if ((Entry & 0x3) == 2) { // Section Type + return 1; + } else { // Page Type + return 0; + } + } else if (Level == Level2){ + if ((Entry & 0x3) == 0) { // Ignored + return 0; + } else { // Page Type + return 1; + } + } else { + DEBUG((EFI_D_ERROR,"MmuEntryIsValidAddress: Level:%d Entry:0x%X\n",(UINT32)Level,(UINT32)Entry)); + ASSERT(0); + return 0; + } +} + +UINT32 MmuEntryGetAddress(MMU_ENTRY Entry) { + if (Entry.Level == Level1) { + if ((Entry.Value & 0x3) == 0) { + return 0; + } else if ((Entry.Value & 0x3) == 2) { // Section Type + return Entry.Value & TT_DESCRIPTOR_SECTION_BASE_ADDRESS_MASK; + } else if ((Entry.Value & 0x3) == 1) { // Level2 Table + MMU_ENTRY Entry = MmuEntryCreate(Level2,(UINT32*)(Entry.Value & 0xFFFFC000),0); + return MmuEntryGetAddress(Entry); + } else { // Page Type + return 0; + } + } else if (Entry.Level == Level2) { + if ((Entry.Value & 0x3) == 0) { // Ignored + return 0; + } else if ((Entry.Value & 0x3) == 1) { // Large Page + return Entry.Value & 0xFFFF0000; + } else if ((Entry.Value & 0x2) == 2) { // Small Page + return Entry.Value & 0xFFFFF000; + } else { + return 0; + } + } else { + ASSERT(0); + return 0; + } +} + +UINT32 MmuEntryGetSize(MMU_ENTRY Entry) { + if (Entry.Level == Level1) { + if ((Entry.Value & 0x3) == 0) { + return 0; + } else if ((Entry.Value & 0x3) == 2) { + if (Entry.Value & (1 << 18)) + return 16*SIZE_1MB; + else + return SIZE_1MB; + } else if ((Entry.Value & 0x3) == 1) { // Level2 Table split 1MB section + return SIZE_1MB; + } else { + DEBUG((EFI_D_ERROR, "MmuEntryGetSize: Value:0x%X",Entry.Value)); + ASSERT(0); + return 0; + } + } else if (Entry.Level == Level2) { + if ((Entry.Value & 0x3) == 0) { // Ignored + return 0; + } else if ((Entry.Value & 0x3) == 1) { // Large Page + return SIZE_64KB; + } else if ((Entry.Value & 0x2) == 2) { // Small Page + return SIZE_4KB; + } else { + ASSERT(0); + return 0; + } + } else { + ASSERT(0); + return 0; + } +} + +CONST CHAR8* MmuEntryGetAttributesName(MMU_ENTRY Entry) { + if (Entry.Level == Level1) { + if (GET_TT_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_SECTION_WRITE_BACK(0)) + return "TT_DESCRIPTOR_SECTION_WRITE_BACK"; + else if (GET_TT_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_SECTION_WRITE_THROUGH(0)) + return "TT_DESCRIPTOR_SECTION_WRITE_THROUGH"; + else if (GET_TT_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_SECTION_DEVICE(0)) + return "TT_DESCRIPTOR_SECTION_DEVICE"; + else if (GET_TT_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_SECTION_UNCACHED(0)) + return "TT_DESCRIPTOR_SECTION_UNCACHED"; + else if (GET_TT_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_SECTION_STRONGLY_ORDER) + return "TT_DESCRIPTOR_SECTION_STRONGLY_ORDERED"; + else { + return "SectionUnknown"; + } + } else if ((Entry.Level == Level2) && ((Entry.Value & 0x2) == 2)) { //Small Page + if (GET_TT_PAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_PAGE_WRITE_BACK) + return "TT_DESCRIPTOR_PAGE_WRITE_BACK"; + else if (GET_TT_PAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_PAGE_WRITE_THROUGH) + return "TT_DESCRIPTOR_PAGE_WRITE_THROUGH"; + else if (GET_TT_PAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_PAGE_DEVICE) + return "TT_DESCRIPTOR_PAGE_DEVICE"; + else if (GET_TT_PAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_PAGE_UNCACHED) + return "TT_DESCRIPTOR_PAGE_UNCACHED"; + else if (GET_TT_PAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_PAGE_STRONGLY_ORDER) + return "TT_DESCRIPTOR_PAGE_STRONGLY_ORDERED"; + else { + return "PageUnknown"; + } + } else if ((Entry.Level == Level2) && ((Entry.Value & 0x3) == 1)) { //Large Page + if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_LARGEPAGE_WRITE_BACK) + return "TT_DESCRIPTOR_LARGEPAGE_WRITE_BACK"; + else if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_LARGEPAGE_WRITE_THROUGH) + return "TT_DESCRIPTOR_LARGEPAGE_WRITE_THROUGH"; + else if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_LARGEPAGE_DEVICE) + return "TT_DESCRIPTOR_LARGEPAGE_DEVICE"; + else if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_LARGEPAGE_UNCACHED) + return "TT_DESCRIPTOR_LARGEPAGE_UNCACHED"; + else { + return "LargePageUnknown"; + } + } else { + ASSERT(0); + return ""; + } +} + +UINT32 MmuEntryGetAttributes(MMU_ENTRY Entry) { + if (Entry.Level == Level1) { + if ((Entry.Value & 0x3) == 0) { + return 0; + } else if ((Entry.Value & 0x3) == 2) { + return GET_TT_ATTRIBUTES(Entry.Value); + } else { + return 0; + } + } else if ((Entry.Level == Level2) && ((Entry.Value & 0x2) == 2)) { //Small Page + if (GET_TT_PAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_PAGE_WRITE_BACK) + return TT_DESCRIPTOR_SECTION_WRITE_BACK(0); + else if (GET_TT_PAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_PAGE_WRITE_THROUGH) + return TT_DESCRIPTOR_SECTION_WRITE_THROUGH(0); + else if (GET_TT_PAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_PAGE_DEVICE) + return TT_DESCRIPTOR_SECTION_DEVICE(0); + else if (GET_TT_PAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_PAGE_UNCACHED) + return TT_DESCRIPTOR_SECTION_UNCACHED(0); + else if (GET_TT_PAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_PAGE_STRONGLY_ORDER) + return TT_DESCRIPTOR_SECTION_STRONGLY_ORDER; + else { + return 0; + } + } else if ((Entry.Level == Level2) && ((Entry.Value & 0x3) == 1)) { //Large Page + if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_LARGEPAGE_WRITE_BACK) + return TT_DESCRIPTOR_SECTION_WRITE_BACK(0); + else if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_LARGEPAGE_WRITE_THROUGH) + return TT_DESCRIPTOR_SECTION_WRITE_THROUGH(0); + else if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_LARGEPAGE_DEVICE) + return TT_DESCRIPTOR_SECTION_DEVICE(0); + else if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_LARGEPAGE_UNCACHED) + return TT_DESCRIPTOR_SECTION_UNCACHED(0); + else { + return 0; + } + } else { + return 0; + } +} + + +MMU_ENTRY DumpMmuLevel(MMU_LEVEL Level, UINT32* Table, MMU_ENTRY PreviousEntry) { + UINT32 Index = 0, Count; + MMU_ENTRY LastEntry, Entry; + + ASSERT((Level == Level1) || (Level == Level2)); + + if (Level == Level1) Count = 4096; + else Count = 256; + + // At Level1, we will get into this function because PreviousEntry is not valid + if (!MmuEntryIsValidAddress((MMU_LEVEL)(Level-1),PreviousEntry.Value)) { + // Find the first valid address + for (; (Index < Count) && (!MmuEntryIsValidAddress(Level,Table[Index])); Index++); + + LastEntry = MmuEntryCreate(Level,Table,Index); + Index++; + } else { + LastEntry = PreviousEntry; + } + + for (; Index < Count; Index++) { + Entry = MmuEntryCreate(Level,Table,Index); + if ((Level == Level1) && ((Entry.Value & 0x3) == 1)) { // We have got a Level2 table redirection + LastEntry = DumpMmuLevel(Level2,(UINT32*)(Entry.Value & 0xFFFFFC00),LastEntry); + } else if (!MmuEntryIsValidAddress(Level,Table[Index])) { + if (MmuEntryIsValidAddress(LastEntry.Level,LastEntry.Value)) { + AsciiPrint("0x%08X-0x%08X\t%a\n", + MmuEntryGetAddress(LastEntry),MmuEntryGetAddress(PreviousEntry)+MmuEntryGetSize(PreviousEntry)-1, + MmuEntryGetAttributesName(LastEntry)); + } + LastEntry = Entry; + } else { + if (MmuEntryGetAttributes(LastEntry) != MmuEntryGetAttributes(Entry)) { + if (MmuEntryIsValidAddress(Level,LastEntry.Value)) { + AsciiPrint("0x%08X-0x%08X\t%a\n", + MmuEntryGetAddress(LastEntry),MmuEntryGetAddress(PreviousEntry)+MmuEntryGetSize(PreviousEntry)-1, + MmuEntryGetAttributesName(LastEntry)); + } + LastEntry = Entry; + } else { + ASSERT(LastEntry.Value != 0); + } + } + PreviousEntry = Entry; + } + + if ((Level == Level1) && (LastEntry.Index != Index) && MmuEntryIsValidAddress(Level,LastEntry.Value)) { + AsciiPrint("0x%08X-0x%08X\t%a\n", + MmuEntryGetAddress(LastEntry),MmuEntryGetAddress(PreviousEntry)+MmuEntryGetSize(PreviousEntry)-1, + MmuEntryGetAttributesName(LastEntry)); + } + + return LastEntry; +} + + +EFI_STATUS +EblDumpMmu ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + UINT32 *TTEntry; + MMU_ENTRY NoEntry; + + TTEntry = ArmGetTTBR0BaseAddress(); + + AsciiPrint ("\nTranslation Table:0x%X\n",TTEntry); + AsciiPrint ("Address Range\t\tAttributes\n"); + AsciiPrint ("____________________________________________________\n"); + + NoEntry.Level = (MMU_LEVEL)200; + DumpMmuLevel(Level1,TTEntry,NoEntry); + + return EFI_SUCCESS; +} -- cgit v1.2.3