/*++ Copyright (c) 1992-2001 Microsoft Corporation Module Name: physical.cpp Abstract: Extensions to read/display physocal memory Environment: User Mode. Revision History: Kshitiz K. Sharma (kksharma) 5/9/2001 --*/ #include "precomp.h" #pragma hdrstop #define PHYS_READ_MATCH_DUMPSIZE 0x100 #define PHYS_FLAG_MESSAGE \ "If you know the caching attributes used for the memory,\n" \ "try specifying [c], [uc] or [wc], as in !dd [c] .\n" \ "WARNING: Incorrect use of these flags will cause unpredictable\n" \ "processor corruption. This may immediately (or at any time in\n" \ "the future until reboot) result in a system hang, incorrect data\n" \ "being displayed or other strange crashes and corruption.\n" ULONG64 g_LastAddress = 0; VOID ReadPhysicalInChunks( ULONG64 Address, PUCHAR Buffer, ULONG BufferSize, ULONG Flags, ULONG ChunkSize, PULONG ActualRead ) { if ((Flags & PHYS_READ_MATCH_DUMPSIZE) && (ChunkSize != 0)) { DWORD i, ret; PUCHAR pReadBuff; Flags &= 0xf; for (i=0, pReadBuff = Buffer; i 0x7e) { ch = '.'; } dprintf("%c", ch); } } dprintf("\n"); } if (!NumEntries) { break; } } Address += cnt; if (!NumEntries) { break; } } } g_LastAddress = Address; return TRUE; } /*++ Routine Description: Reverse sign extension of the value returned by GetExpression() based on the assumption that no physical address may be bigger than 0xfffffff00000000. Arguments: Val - points to the value to reverse sign extension Return Value: None. --*/ void ReverseSignExtension(ULONG64* Val) { if ((*Val & 0xffffffff00000000) == 0xffffffff00000000) { *Val &= 0x00000000ffffffff; } } PCSTR GetPhyFlags(PCSTR Args, PULONG Flags) { *Flags = PHYS_FLAG_DEFAULT; while (*Args && (*Args == ' ' || *Args == '\t')) { ++Args; } if (*Args == '[') { Args++; if (*Args == 'c') { *Flags = PHYS_FLAG_CACHED; Args++; } else if (*Args == 'u' && *(Args + 1) == 'c') { *Flags = PHYS_FLAG_UNCACHED; Args += 2; } else if (*Args == 'w' && *(Args + 1) == 'c') { *Flags = PHYS_FLAG_WRITE_COMBINED; Args += 2; } if (*Args != ']') { *Flags = PHYS_FLAG_DEFAULT; dprintf("Unknown physical memory caching attribute\n"); } else { Args++; } } if (*Args == '-' || *Args == '\\') { ++Args; if (tolower(*Args) == 'm') { *Flags |= PHYS_READ_MATCH_DUMPSIZE; } else { dprintf("Bad argument -%s\n", Args); } ++Args; } return Args; } void GetPhyDumpArgs( PCSTR Args, PULONG64 Address, PULONG Range, PULONG Flags ) { CHAR Buffer[100]={0}; *Flags = PHYS_FLAG_DEFAULT; if(*Args == '\0') { *Address=g_LastAddress; } else { Args = GetPhyFlags(Args, Flags); while (*Args && (*Args == ' ' || *Args == '\t')) { ++Args; } if(*Args == '\0') { *Address=g_LastAddress; } else { GetExpressionEx(Args, Address, &Args); ReverseSignExtension(Address); *Address &= (~0x3); // Truncate to dword boundary g_LastAddress=*Address; while (*Args && (*Args == ' ' || *Args == '\t')) { ++Args; } if (*Args == 'l' || *Args == 'L') { ++Args; *Range = (ULONG) GetExpression(Args); } } } return; } DECLARE_API( db ) /*++ Routine Description: Does a read of 16 ULONGS from the physical memory of the target machine Arguments: args - Supplies physical address Return Value: None. --*/ { ULONG64 Address = 0; ULONG Range = 0; ULONG Flags; GetPhyDumpArgs(args, &Address, &Range, &Flags); if (!Range) { Range = 128; } DumpPhysicalMemory(Address, Range, 1, TRUE, Flags); return S_OK; } DECLARE_API( dd ) /*++ Routine Description: Does a read of 16 ULONGS from the physical memory of the target machine Arguments: args - Supplies physical address Return Value: None. --*/ { ULONG64 Address = 0; ULONG Range = 0; ULONG Flags; GetPhyDumpArgs(args, &Address, &Range, &Flags); if (!Range) { Range = 32; } DumpPhysicalMemory(Address, Range, 4, FALSE, Flags); return S_OK; } DECLARE_API( dw ) /*++ Routine Description: Does a read of 16 ULONGS from the physical memory of the target machine Arguments: args - Supplies physical address Return Value: None. --*/ { ULONG64 Address = 0; ULONG Range = 0; ULONG Flags; GetPhyDumpArgs(args, &Address, &Range, &Flags); if (!Range) { Range = 64; } DumpPhysicalMemory(Address, Range, 2, FALSE, Flags); return S_OK; } DECLARE_API( dp ) /*++ Routine Description: Does a read of 16 ULONGS from the physical memory of the target machine Arguments: args - Supplies physical address Return Value: None. --*/ { ULONG64 Address = 0; ULONG Range = 0; ULONG Flags; GetPhyDumpArgs(args, &Address, &Range, &Flags); if (!Range) { Range = IsPtr64() ? 16 : 32; } DumpPhysicalMemory(Address, Range, IsPtr64() ? 8 : 4, FALSE, Flags); return S_OK; } DECLARE_API( dc ) /*++ Routine Description: Does a read of N ULONGS from the physical memory of the target machine, dumping both hex and ASCII. Arguments: args - Supplies physical address Return Value: None. --*/ { ULONG64 Address = 0; ULONG Range = 0; ULONG Flags; GetPhyDumpArgs(args, &Address, &Range, &Flags); if (!Range) { Range = 32; } DumpPhysicalMemory(Address, Range, 4, TRUE, Flags); return S_OK; } DECLARE_API( du ) /*++ Routine Description: Does a read of 16 ULONGS from the physical memory of the target machine Arguments: args - Supplies physical address Return Value: None. --*/ { ULONG64 Address = 0; ULONG Range = 0, ActualRead; WCHAR Buffer[MAX_PATH]={0}; ULONG Flags; GetPhyDumpArgs(args, &Address, &Range, &Flags); if (Range>MAX_PATH) { Range = MAX_PATH; } if (!Range) { Range = 16; } ReadPhysicalWithFlags(Address,Buffer,Range * sizeof(WCHAR),Flags,&ActualRead); if (ActualRead != Range*sizeof(WCHAR)) { dprintf("Physical memory read at %I64lx failed\n", Address); if (Flags == PHYS_FLAG_DEFAULT && ActualRead == 0) { dprintf(PHYS_FLAG_MESSAGE); } return FALSE; } else { ULONG cnt; dprintf("#%8I64lx \"", Address); for (ULONG d=0; d < Range; d++) { WCHAR ch = Buffer[d]; if (ch == 0) { break; } if (ch < 0x20 || ch > 0x7e) { ch = '.'; } dprintf("%wc", ch); } dprintf("\"\n"); } return S_OK; } DECLARE_API( ed ) /*++ Routine Description: Writes a sequence of ULONGs into a given physical address on the target machine. Arguments: arg - Supplies both the target address and the data in the form of "PHYSICAL_ADDRESS ULONG [ULONG, ULONG,...]" Return Value: None. --*/ { ULONG64 Address = 0; ULONG Buffer; ULONG ActualWritten=0; PCHAR NextToken; ULONG Flags; args = GetPhyFlags(args, &Flags); Address = GetExpression(args); strtok((PSTR)args," \t,"); // The first token is the address // Since we're picking off one ULONG at a time, we'll make // one DbgKdWritePhysicalMemoryAddress call per ULONG. This // is slow, but easy to code. while((NextToken=strtok(NULL," \t,")) != NULL) { if (!sscanf(NextToken,"%lx",&Buffer)) { break; } WritePhysicalWithFlags(Address,&Buffer,sizeof(Buffer),Flags, &ActualWritten); if (ActualWritten != sizeof(Buffer)) { dprintf("Physical memory write at %I64lx failed\n", Address); if (Flags == PHYS_FLAG_DEFAULT && ActualWritten == 0) { dprintf(PHYS_FLAG_MESSAGE); } } Address+=sizeof(Buffer); } return S_OK; } DECLARE_API( eb ) /*++ Routine Description: Writes a sequence of BYTEs into a given physical address on the target machine. Arguments: arg - Supplies both the target address and the data in the form of "PHYSICAL_ADDRESS ULONG [ULONG, ULONG,...]" Return Value: None. --*/ { ULONG64 Address = 0; ULONG Buffer; UCHAR c; ULONG ActualWritten; PCHAR NextToken; ULONG Flags; UNREFERENCED_PARAMETER (Client); args = GetPhyFlags(args, &Flags); Address = GetExpression(args); strtok((PSTR)args," \t,"); // The first token is the address // Since we're picking off one BYTE at a time, we'll make // one DbgKdWritePhysicalMemoryAddress call per BYTE. This // is slow, but easy to code. while((NextToken=strtok(NULL," \t,")) != NULL) { if (!sscanf(NextToken,"%lx",&Buffer)) { break; } c = (UCHAR)Buffer; WritePhysicalWithFlags(Address,&c,sizeof(UCHAR),Flags,&ActualWritten); if (ActualWritten != sizeof(UCHAR)) { dprintf("Physical memory write at %I64lx failed\n", Address); if (Flags == PHYS_FLAG_DEFAULT && ActualWritten == 0) { dprintf(PHYS_FLAG_MESSAGE); } } Address+=sizeof(UCHAR); } return S_OK; }