diff options
Diffstat (limited to 'cfe/cfe/ui/ui_examcmds.c')
-rw-r--r-- | cfe/cfe/ui/ui_examcmds.c | 713 |
1 files changed, 713 insertions, 0 deletions
diff --git a/cfe/cfe/ui/ui_examcmds.c b/cfe/cfe/ui/ui_examcmds.c new file mode 100644 index 0000000..91edeee --- /dev/null +++ b/cfe/cfe/ui/ui_examcmds.c @@ -0,0 +1,713 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Memory dump commands File: ui_examcmds.c + * + * UI functions for examining data in various ways + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_error.h" +#include "cfe_console.h" + +#include "ui_command.h" +#include "cfe.h" +#include "disasm.h" + +#include "addrspace.h" +#include "exchandler.h" + + +static int ui_cmd_memdump(ui_cmdline_t *cmd,int argc,char *argv[]); +static int ui_cmd_memedit(ui_cmdline_t *cmd,int argc,char *argv[]); +static int ui_cmd_memfill(ui_cmdline_t *cmd,int argc,char *argv[]); +static int ui_cmd_disasm(ui_cmdline_t *cmd,int argc,char *argv[]); + +#ifdef __long64 +#define XTOI(x) xtoq(x) +#else +#define XTOI(x) xtoi(x) +#endif + +int ui_init_examcmds(void); + + +#define ATYPE_SIZE_NONE 0 +#define ATYPE_SIZE_BYTE 1 +#define ATYPE_SIZE_HALF 2 +#define ATYPE_SIZE_WORD 4 +#define ATYPE_SIZE_QUAD 8 +#define ATYPE_SIZE_MASK 0x0F + +#define ATYPE_TYPE_NONE 0 +#define ATYPE_TYPE_PHYS 0x10 +#define ATYPE_TYPE_KERN 0x20 +#define ATYPE_TYPE_MASK 0xF0 + +static long prev_addr = 0; /* initialized below in ui_init_examcmds */ +static int prev_length = 256; +static int prev_dlength = 16; +static int prev_wtype = ATYPE_SIZE_WORD | ATYPE_TYPE_KERN; + +static int getaddrargs(ui_cmdline_t *cmd,int *curtype,long *addr,int *length) +{ + int atype = *curtype; + long newaddr; + int newlen; + char *x; + long wlen; + + if (cmd_sw_isset(cmd,"-b")) { + atype &= ~ATYPE_SIZE_MASK; + atype |= ATYPE_SIZE_BYTE; + } + else if (cmd_sw_isset(cmd,"-h")) { + atype &= ~ATYPE_SIZE_MASK; + atype |= ATYPE_SIZE_HALF; + } + else if (cmd_sw_isset(cmd,"-w")) { + atype &= ~ATYPE_SIZE_MASK; + atype |= ATYPE_SIZE_WORD; + } + else if (cmd_sw_isset(cmd,"-q")) { + atype &= ~ATYPE_SIZE_MASK; + atype |= ATYPE_SIZE_QUAD; + } + + wlen = atype & ATYPE_SIZE_MASK; + if (wlen == 0) wlen = 1; /* bytes are the default */ + + if (cmd_sw_isset(cmd,"-p")) { + atype &= ~ATYPE_TYPE_MASK; + atype |= ATYPE_TYPE_PHYS; + } + else if (cmd_sw_isset(cmd,"-v")) { + atype &= ~ATYPE_TYPE_MASK; + atype |= ATYPE_TYPE_KERN; + } + + *curtype = atype; + + if (addr) { + x = cmd_getarg(cmd,0); + if (x) { + if (strcmp(x,".") == 0) newaddr = *addr; + else { + /* + * hold on to your lunch, this is really, really bad! + * Make 64-bit addresses expressed as 8-digit numbers + * sign extend automagically. Saves typing, but is very + * gross. + */ + int longaddr = 0; + longaddr = strlen(x); + if (memcmp(x,"0x",2) == 0) longaddr -= 2; + longaddr = (longaddr > 8) ? 1 : 0; + + if (longaddr) newaddr = (long) xtoq(x); + else newaddr = (long) xtoi(x); + } + *addr = newaddr & ~(wlen - 1); /* align to natural boundary */ + } + } + + if (length) { + x = cmd_getarg(cmd,1); + if (x) { + newlen = (long) xtoi(x); + *length = newlen; + } + } + + return 0; + +} + +static int stuffmem(long addr,int wlen,char *tail) +{ + char *tok; + int count = 0; + uint8_t b; + uint16_t h; + uint32_t w; + uint64_t q; + int res = 0; + + addr &= ~(wlen-1); + + while ((tok = gettoken(&tail))) { + switch (wlen) { + default: + case 1: + b = (uint8_t) xtoq(tok); + if ((res = mem_poke(addr, b, MEM_BYTE))) { + /*Did not edit*/ + return res; + } + break; + case 2: + h = (uint16_t) xtoq(tok); + if ((res = mem_poke(addr, h, MEM_HALFWORD))) { + /*Did not edit*/ + return res; + } + break; + case 4: + w = (uint32_t) xtoq(tok); + if ((res = mem_poke(addr, w, MEM_WORD))) { + /*Did not edit*/ + return res; + } + break; + case 8: + q = (uint64_t) xtoq(tok); + if ((res = mem_poke(addr, q, MEM_QUADWORD))) { + /*Did not edit*/ + return res; + } + break; + } + + addr += wlen; + count++; + } + + return count; +} + +static int dumpmem(long addr,long dispaddr,int length,int wlen) +{ + int idx,x; + uint8_t b; + uint16_t h; + uint32_t w; + uint64_t q; + int res = 0; + + /* + * The reason we save the line in this union is to provide the + * property that the dump command will only touch the + * memory once. This might be useful when looking at + * device registers. + */ + + union { + uint8_t bytes[16]; + uint16_t halves[8]; + uint32_t words[4]; + uint64_t quads[2]; + } line; + + addr &= ~(wlen-1); + + for (idx = 0; idx < length; idx += 16) { + xprintf("%P%c ",dispaddr+idx,(dispaddr != addr) ? '%' : ':'); + switch (wlen) { + default: + case 1: + for (x = 0; x < 16; x++) { + if (idx+x < length) { + if ((res = mem_peek(&b, (addr+idx+x), MEM_BYTE))) { + return res; + } + line.bytes[x] = b; + xprintf("%02X ",b); + } + else { + xprintf(" "); + } + } + break; + case 2: + for (x = 0; x < 16; x+=2) { + if (idx+x < length) { + if ((res = mem_peek(&h, (addr+idx+x), MEM_HALFWORD))) { + return res; + } + line.halves[x/2] = h; + xprintf("%04X ",h); + } + else { + xprintf(" "); + } + } + break; + case 4: + for (x = 0; x < 16; x+=4) { + if (idx+x < length) { + + if ((res = mem_peek(&w , (addr+idx+x), MEM_WORD))) { + return res; + } + line.words[x/4] = w; + xprintf("%08X ",w); + } + else { + xprintf(" "); + } + } + break; + case 8: + for (x = 0; x < 16; x+=8) { + if (idx+x < length) { + if ((res = mem_peek(&q, (addr+idx+x), MEM_QUADWORD))) { + return res; + } + line.quads[x/8] = q; + xprintf("%016llX ",q); + } + else { + xprintf(" "); + } + } + break; + } + + xprintf(" "); + for (x = 0; x < 16; x++) { + if (idx+x < length) { + b = line.bytes[x]; + if ((b < 32) || (b > 127)) xprintf("."); + else xprintf("%c",b); + } + else { + xprintf(" "); + } + } + xprintf("\n"); + } + + return 0; +} + +static int ui_cmd_memedit(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + uint8_t b; + uint16_t h; + uint32_t w; + uint64_t q; + + long addr; + char *vtext; + int wlen; + int count; + int idx = 1; + int stuffed = 0; + int res = 0; + + getaddrargs(cmd,&prev_wtype,&prev_addr,NULL); + + wlen = prev_wtype & ATYPE_SIZE_MASK; + + vtext = cmd_getarg(cmd,idx++); + + addr = prev_addr; + + while (vtext) { + count = stuffmem(addr,wlen,vtext); + if (count < 0) { + ui_showerror(count,"Could not modify memory"); + return count; /* error */ + } + addr += count*wlen; + prev_addr += count*wlen; + stuffed += count; + vtext = cmd_getarg(cmd,idx++); + } + + if (stuffed == 0) { + char line[256]; + char prompt[32]; + + xprintf("Type '.' to exit, '-' to back up, '=' to dump memory.\n"); + for (;;) { + + addr = prev_addr; + if ((prev_wtype & ATYPE_TYPE_MASK) == ATYPE_TYPE_PHYS) { + addr = UNCADDR(addr); + } + + xprintf("%P%c ",prev_addr,(addr != prev_addr) ? '%' : ':'); + + switch (wlen) { + default: + case 1: + if ((res = mem_peek(&b, addr, MEM_BYTE))) { + return res; + } + xsprintf(prompt,"[%02X]: ", b); + break; + case 2: + if ((res = mem_peek(&h, addr, MEM_HALFWORD))) { + return res; + } + xsprintf(prompt,"[%04X]: ",h); + break; + case 4: + if ((res = mem_peek(&w, addr, MEM_WORD))) { + return res; + } + xsprintf(prompt,"[%08X]: ",w); + break; + case 8: + if ((res = mem_peek(&q, addr, MEM_QUADWORD))) { + return res; + } + xsprintf(prompt,"[%016llX]: ",q); + break; + } + + console_readline(prompt,line,sizeof(line)); + if (line[0] == '-') { + prev_addr -= wlen; + continue; + } + if (line[0] == '=') { + dumpmem(prev_addr,prev_addr,16,wlen); + continue; + } + if (line[0] == '.') { + break; + } + if (line[0] == '\0') { + prev_addr += wlen; + continue; + } + count = stuffmem(addr,wlen,line); + if (count < 0) return count; + if (count == 0) break; + prev_addr += count*wlen; + } + } + + return 0; +} + +static int ui_cmd_memfill(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + long addr; + char *atext; + int wlen; + int idx = 2; + int len; + uint64_t pattern; + uint8_t *b_ptr; + uint16_t *h_ptr; + uint32_t *w_ptr; + uint64_t *q_ptr; + int res; + + getaddrargs(cmd,&prev_wtype,&prev_addr,&len); + + atext = cmd_getarg(cmd,idx++); + if (!atext) return ui_showusage(cmd); + pattern = xtoq(atext); + + addr = prev_addr; + + if ((prev_wtype & ATYPE_TYPE_MASK) == ATYPE_TYPE_PHYS) { + addr = UNCADDR(addr); + } + + wlen = prev_wtype & ATYPE_SIZE_MASK; + + switch (wlen) { + case 1: + b_ptr = (uint8_t *) addr; + while (len > 0) { + if ((res = mem_poke( ((long)(b_ptr)), pattern, MEM_BYTE))) { + /*Did not edit*/ + return 0; + } + b_ptr++; + len--; + } + break; + case 2: + h_ptr = (uint16_t *) addr; + while (len > 0) { + if ((res = mem_poke( ((long)(h_ptr)), pattern, MEM_HALFWORD))) { + return 0; + } + h_ptr++; + len--; + } + break; + case 4: + w_ptr = (uint32_t *) addr; + while (len > 0) { + if ((res = mem_poke( ((long)(w_ptr)), pattern, MEM_WORD))) { + return -1; + } + w_ptr++; + len--; + } + break; + case 8: + q_ptr = (uint64_t *) addr; + while (len > 0) { + if ((res = mem_poke( ((long)(q_ptr)), pattern, MEM_QUADWORD))) { + return 0; + } + q_ptr++; + len--; + } + break; + } + + return 0; +} + + +#define FILL(ptr,len,pattern) printf("Pattern: %016llX\n",pattern); \ + for (idx = 0; idx < len; idx++) ptr[idx] = pattern +#define CHECK(ptr,len,pattern) for (idx = 0; idx < len; idx++) { \ + if (ptr[idx]!=pattern) {printf("Mismatch at %016llX: Expected %016llX got %016llX", \ + (uint64_t) (uintptr_t) &(ptr[idx]),pattern,ptr[idx]); \ + error = 1; loopmode = 0;break;} \ + } + +#define MEMTEST(ptr,len,pattern) if (!error) { FILL(ptr,len,pattern) ; CHECK(ptr,len,pattern); } + +static int ui_cmd_memtest(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + long addr = 0; + int len = 0; + int wtype = 0; + int wlen; + int idx = 0; + uint64_t *ptr; + int error = 0; + int loopmode = 0; + int pass =0; + + getaddrargs(cmd,&wtype,&addr,&len); + + wlen = 8; + addr &= ~(wlen-1); + + if ((prev_wtype & ATYPE_TYPE_MASK) == ATYPE_TYPE_PHYS) { + addr = UNCADDR(addr); + } + + if (cmd_sw_isset(cmd,"-loop")) { + loopmode = 1; + } + + len /= wlen; + + ptr = (uint64_t *) addr; + pass = 0; + for (;;) { + if (loopmode) { + printf("Pass %d\n",pass); + if (console_status()) break; + } + MEMTEST(ptr,len,(idx*8)); + MEMTEST(ptr,len, 0); + MEMTEST(ptr,len,0xFFFFFFFFFFFFFFFF); + MEMTEST(ptr,len,0x5555555555555555); + MEMTEST(ptr,len,0xAAAAAAAAAAAAAAAA); + MEMTEST(ptr,len,0xFF00FF00FF00FF00); + MEMTEST(ptr,len,0x00FF00FF00FF00FF); + if (!loopmode) break; + pass++; + } + + return 0; +} + +static int ui_cmd_memdump(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + long addr; + int res; + + getaddrargs(cmd,&prev_wtype,&prev_addr,&prev_length); + + addr = prev_addr; + if ((prev_wtype & ATYPE_TYPE_MASK) == ATYPE_TYPE_PHYS) { + addr = UNCADDR(addr); + } + + res = dumpmem(addr, + prev_addr, + prev_length, + prev_wtype & ATYPE_SIZE_MASK); + + if (res < 0) { + ui_showerror(res,"Could not display memory"); + } + else { + prev_addr += prev_length; + } + + return res; +} + +static int ui_cmd_disasm(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + long addr; + char buf[512]; + int idx; + uint32_t inst; + int res; + + getaddrargs(cmd,&prev_wtype,&prev_addr,&prev_dlength); + + prev_addr &= ~3; + + addr = prev_addr; + if ((prev_wtype & ATYPE_TYPE_MASK) == ATYPE_TYPE_PHYS) { + addr = UNCADDR(addr); + } + + for (idx = 0; idx < prev_dlength; idx++) { + if ((res = mem_peek(&inst, addr, MEM_WORD))) { + ui_showerror(res,"Could not disassemble memory"); + return res; + } + disasm_inst(buf,sizeof(buf),inst,(uint64_t) prev_addr); + xprintf("%P%c %08x %s\n",prev_addr,(addr != prev_addr) ? '%' : ':',inst,buf); + addr += 4; + prev_addr += 4; + } + + return 0; +} + +int ui_init_examcmds(void) +{ + cmd_addcmd("u", + ui_cmd_disasm, + NULL, + "Disassemble instructions.", + "u [addr [length]]\n\n" + "This command disassembles instructions at the specified address.\n" + "CFE will display standard register names and symbolic names for\n" + "certain CP0 registers. The 'u' command remembers the last address\n" + "that was disassembled so you can enter 'u' again with no parameters\n" + "to continue a previous request.\n", + "-p;Address is an uncached physical address|" + "-v;Address is a kernel virtual address"); + + + cmd_addcmd("d", + ui_cmd_memdump, + NULL, + "Dump memory.", + "d [-b|-h|-w|-q] [addr [length]]\n\n" + "This command displays data from memory as bytes, halfwords, words,\n" + "or quadwords. ASCII text, if present, will appear to the right of\n" + "the hex data. The dump command remembers the previous word size,\n" + "dump length and last displayed address, so you can enter 'd' again\n" + "to continue a previous dump request.", + "-b;Dump memory as bytes|" + "-h;Dump memory as halfwords (16-bits)|" + "-w;Dump memory as words (32-bits)|" + "-q;Dump memory as quadwords (64-bits)|" + "-p;Address is an uncached physical address|" + "-v;Address is a kernel virtual address"); + + + cmd_addcmd("e", + ui_cmd_memedit, + NULL, + "Modify contents of memory.", + "e [-b|-h|-w|-q] [addr [data...]]\n\n" + "This command modifies the contents of memory. If you do not specify\n" + "data on the command line, CFE will prompt for it. When prompting for\n" + "data you may enter '-' to back up, '=' to dump memory at the current\n" + "location, or '.' to exit edit mode.", + "-b;Edit memory as bytes|" + "-h;Edit memory as halfwords (16-bits)|" + "-w;Edit memory as words (32-bits)|" + "-q;Edit memory as quadwords (64-bits)|" + "-p;Address is an uncached physical address|" + "-v;Address is a kernel virtual address"); + + cmd_addcmd("f", + ui_cmd_memfill, + NULL, + "Fill contents of memory.", + "f [-b|-h|-w|-q] addr length pattern\n\n" + "This command modifies the contents of memory. You can specify the\n" + "starting address, length, and pattern of data to fill (in hex)\n", + "-b;Edit memory as bytes|" + "-h;Edit memory as halfwords (16-bits)|" + "-w;Edit memory as words (32-bits)|" + "-q;Edit memory as quadwords (64-bits)|" + "-p;Address is an uncached physical address|" + "-v;Address is a kernel virtual address"); + + cmd_addcmd("memtest", + ui_cmd_memtest, + NULL, + "Test memory.", + "memtest [options] addr length\n\n" + "This command tests memory. It is a very crude test, so don't\n" + "rely on it for anything really important. Addr and length are in hex\n", + "-p;Address is an uncached physical address|" + "-v;Address is a kernel virtual address|" + "-loop;Loop till keypress"); + + + prev_addr = KERNADDR(0); + + return 0; +} + + + + + + + + + + + |