1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * Memory dump commands File: ui_examcmds.c 5 * 6 * UI functions for examining data in various ways 7 * 8 * Author: Mitch Lichtenberg 9 * 10 ********************************************************************* 11 * 12 * Copyright 2000,2001,2002,2003 13 * Broadcom Corporation. All rights reserved. 14 * 15 * This software is furnished under license and may be used and 16 * copied only in accordance with the following terms and 17 * conditions. Subject to these conditions, you may download, 18 * copy, install, use, modify and distribute modified or unmodified 19 * copies of this software in source and/or binary form. No title 20 * or ownership is transferred hereby. 21 * 22 * 1) Any source code used, modified or distributed must reproduce 23 * and retain this copyright notice and list of conditions 24 * as they appear in the source file. 25 * 26 * 2) No right is granted to use any trade name, trademark, or 27 * logo of Broadcom Corporation. The "Broadcom Corporation" 28 * name may not be used to endorse or promote products derived 29 * from this software without the prior written permission of 30 * Broadcom Corporation. 31 * 32 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR 33 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED 34 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 35 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 36 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 37 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, 38 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 39 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 40 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 41 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 42 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 43 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 44 * THE POSSIBILITY OF SUCH DAMAGE. 45 ********************************************************************* */ 46 47 48#include "cfe.h" 49#include "ui_command.h" 50#include "disasm.h" 51 52#include "lib_hssubr.h" 53#include "lib_memfuncs.h" 54 55 56static int ui_cmd_memdump(ui_cmdline_t *cmd,int argc,char *argv[]); 57static int ui_cmd_memedit(ui_cmdline_t *cmd,int argc,char *argv[]); 58static int ui_cmd_memfill(ui_cmdline_t *cmd,int argc,char *argv[]); 59static int ui_cmd_disasm(ui_cmdline_t *cmd,int argc,char *argv[]); 60 61#if CPUCFG_REGS64 62#define XTOI(x) xtoq(x) 63#define PTRFMT "%016llX" 64#else 65#define XTOI(x) xtoi(x) 66#define PTRFMT "%08lX" 67#endif 68 69int ui_init_examcmds(void); 70int dumpmem(hsaddr_t addr,hsaddr_t dispaddr,int length,int wlen); 71 72 73#define ATYPE_SIZE_NONE 0 74#define ATYPE_SIZE_BYTE 1 75#define ATYPE_SIZE_HALF 2 76#define ATYPE_SIZE_WORD 4 77#define ATYPE_SIZE_QUAD 8 78#define ATYPE_SIZE_MASK 0x0F 79 80#define ATYPE_TYPE_NONE 0 81#define ATYPE_TYPE_PHYS 0x10 82#define ATYPE_TYPE_KERN 0x20 83#define ATYPE_TYPE_MASK 0xF0 84 85static hsaddr_t prev_addr = 0; /* initialized below in ui_init_examcmds */ 86static int prev_length = 256; 87static int prev_dlength = 16; 88static int prev_wtype = ATYPE_SIZE_WORD | ATYPE_TYPE_KERN; 89 90static int getaddrargs(ui_cmdline_t *cmd,int *curtype,hsaddr_t *addr,int *length) 91{ 92 int atype = *curtype; 93 hsaddr_t newaddr; 94 int newlen; 95 char *x; 96 hsaddr_t wlen; 97 98 if (cmd_sw_isset(cmd,"-b")) { 99 atype &= ~ATYPE_SIZE_MASK; 100 atype |= ATYPE_SIZE_BYTE; 101 } 102 else if (cmd_sw_isset(cmd,"-h")) { 103 atype &= ~ATYPE_SIZE_MASK; 104 atype |= ATYPE_SIZE_HALF; 105 } 106 else if (cmd_sw_isset(cmd,"-w")) { 107 atype &= ~ATYPE_SIZE_MASK; 108 atype |= ATYPE_SIZE_WORD; 109 } 110 else if (cmd_sw_isset(cmd,"-q")) { 111 atype &= ~ATYPE_SIZE_MASK; 112 atype |= ATYPE_SIZE_QUAD; 113 } 114 115 wlen = atype & ATYPE_SIZE_MASK; 116 if (wlen == 0) wlen = 1; /* bytes are the default */ 117 118 if (cmd_sw_isset(cmd,"-p")) { 119 atype &= ~ATYPE_TYPE_MASK; 120 atype |= ATYPE_TYPE_PHYS; 121 } 122 else if (cmd_sw_isset(cmd,"-v")) { 123 atype &= ~ATYPE_TYPE_MASK; 124 atype |= ATYPE_TYPE_KERN; 125 } 126 127 *curtype = atype; 128 129 if (addr) { 130 x = cmd_getarg(cmd,0); 131 if (x) { 132 if (strcmp(x,".") == 0) newaddr = *addr; 133 else { 134 /* 135 * hold on to your lunch, this is really, really bad! 136 * Make 64-bit addresses expressed as 8-digit numbers 137 * sign extend automagically. Saves typing, but is very 138 * gross. 139 */ 140 int longaddr = 0; 141 longaddr = strlen(x); 142 if (memcmp(x,"0x",2) == 0) longaddr -= 2; 143 longaddr = (longaddr > 8) ? 1 : 0; 144 145 if (longaddr) newaddr = (hsaddr_t) xtoq(x); 146 else newaddr = (hsaddr_t) xtoi(x); 147 } 148 *addr = newaddr & ~(wlen - 1); /* align to natural boundary */ 149 } 150 } 151 152 if (length) { 153 x = cmd_getarg(cmd,1); 154 if (x) { 155 newlen = (long) xtoi(x); 156 *length = newlen; 157 } 158 } 159 160 return 0; 161 162} 163 164static int stuffmem(hsaddr_t addr,int wlen,char *tail) 165{ 166 char *tok; 167 int count = 0; 168 uint8_t b; 169 uint16_t h; 170 uint32_t w; 171 uint64_t q; 172 int res = 0; 173 174 addr &= ~(wlen-1); 175 176 while ((tok = gettoken(&tail))) { 177 switch (wlen) { 178 default: 179 case 1: 180 b = (uint8_t) xtoq(tok); 181 if ((res = mem_poke(addr, b, MEM_BYTE))) { 182 /*Did not edit*/ 183 return res; 184 } 185 break; 186 case 2: 187 h = (uint16_t) xtoq(tok); 188 if ((res = mem_poke(addr, h, MEM_HALFWORD))) { 189 /*Did not edit*/ 190 return res; 191 } 192 break; 193 case 4: 194 w = (uint32_t) xtoq(tok); 195 if ((res = mem_poke(addr, w, MEM_WORD))) { 196 /*Did not edit*/ 197 return res; 198 } 199 break; 200 case 8: 201 q = (uint64_t) xtoq(tok); 202 if ((res = mem_poke(addr, q, MEM_QUADWORD))) { 203 /*Did not edit*/ 204 return res; 205 } 206 break; 207 } 208 209 addr += wlen; 210 count++; 211 } 212 213 return count; 214} 215 216int dumpmem(hsaddr_t addr,hsaddr_t dispaddr,int length,int wlen) 217{ 218 int idx,x; 219 uint8_t b; 220 uint16_t h; 221 uint32_t w; 222 uint64_t q; 223 int res = 0; 224 225 /* 226 * The reason we save the line in this union is to provide the 227 * property that the dump command will only touch the 228 * memory once. This might be useful when looking at 229 * device registers. 230 */ 231 232 union { 233 uint8_t bytes[16]; 234 uint16_t halves[8]; 235 uint32_t words[4]; 236 uint64_t quads[2]; 237 } line; 238 239 addr &= ~(wlen-1); 240 241 for (idx = 0; idx < length; idx += 16) { 242 xprintf(PTRFMT "%c ",dispaddr+idx,(dispaddr != addr) ? '%' : ':'); 243 switch (wlen) { 244 default: 245 case 1: 246 for (x = 0; x < 16; x++) { 247 if (idx+x < length) { 248 if ((res = mem_peek(&b, (addr+idx+x), MEM_BYTE))) { 249 return res; 250 } 251 line.bytes[x] = b; 252 xprintf("%02X ",b); 253 } 254 else { 255 xprintf(" "); 256 } 257 } 258 break; 259 case 2: 260 for (x = 0; x < 16; x+=2) { 261 if (idx+x < length) { 262 if ((res = mem_peek(&h, (addr+idx+x), MEM_HALFWORD))) { 263 return res; 264 } 265 line.halves[x/2] = h; 266 xprintf("%04X ",h); 267 } 268 else { 269 xprintf(" "); 270 } 271 } 272 break; 273 case 4: 274 for (x = 0; x < 16; x+=4) { 275 if (idx+x < length) { 276 277 if ((res = mem_peek(&w , (addr+idx+x), MEM_WORD))) { 278 return res; 279 } 280 line.words[x/4] = w; 281 xprintf("%08X ",w); 282 } 283 else { 284 xprintf(" "); 285 } 286 } 287 break; 288 case 8: 289 for (x = 0; x < 16; x+=8) { 290 if (idx+x < length) { 291 if ((res = mem_peek(&q, (addr+idx+x), MEM_QUADWORD))) { 292 return res; 293 } 294 line.quads[x/8] = q; 295 xprintf("%016llX ",q); 296 } 297 else { 298 xprintf(" "); 299 } 300 } 301 break; 302 } 303 304 xprintf(" "); 305 for (x = 0; x < 16; x++) { 306 if (idx+x < length) { 307 b = line.bytes[x]; 308 if ((b < 32) || (b > 127)) xprintf("."); 309 else xprintf("%c",b); 310 } 311 else { 312 xprintf(" "); 313 } 314 } 315 xprintf("\n"); 316 } 317 318 return 0; 319} 320 321static int ui_cmd_memedit(ui_cmdline_t *cmd,int argc,char *argv[]) 322{ 323 uint8_t b; 324 uint16_t h; 325 uint32_t w; 326 uint64_t q; 327 328 hsaddr_t addr; 329 char *vtext; 330 int wlen; 331 int count; 332 int idx = 1; 333 int stuffed = 0; 334 int res = 0; 335 336 getaddrargs(cmd,&prev_wtype,&prev_addr,NULL); 337 338 wlen = prev_wtype & ATYPE_SIZE_MASK; 339 340 vtext = cmd_getarg(cmd,idx++); 341 342 addr = prev_addr; 343 344 while (vtext) { 345 count = stuffmem(addr,wlen,vtext); 346 if (count < 0) { 347 ui_showerror(count,"Could not modify memory"); 348 return count; /* error */ 349 } 350 addr += count*wlen; 351 prev_addr += count*wlen; 352 stuffed += count; 353 vtext = cmd_getarg(cmd,idx++); 354 } 355 356 if (stuffed == 0) { 357 char line[256]; 358 char prompt[32]; 359 360 xprintf("Type '.' to exit, '-' to back up, '=' to dump memory.\n"); 361 for (;;) { 362 363 addr = prev_addr; 364 if ((prev_wtype & ATYPE_TYPE_MASK) == ATYPE_TYPE_PHYS) { 365 addr = UNCADDR(addr); 366 } 367 368 xprintf(PTRFMT "%c ",prev_addr,(addr != prev_addr) ? '%' : ':'); 369 370 switch (wlen) { 371 default: 372 case 1: 373 if ((res = mem_peek(&b, addr, MEM_BYTE))) { 374 return res; 375 } 376 xsprintf(prompt,"[%02X]: ", b); 377 break; 378 case 2: 379 if ((res = mem_peek(&h, addr, MEM_HALFWORD))) { 380 return res; 381 } 382 xsprintf(prompt,"[%04X]: ",h); 383 break; 384 case 4: 385 if ((res = mem_peek(&w, addr, MEM_WORD))) { 386 return res; 387 } 388 xsprintf(prompt,"[%08X]: ",w); 389 break; 390 case 8: 391 if ((res = mem_peek(&q, addr, MEM_QUADWORD))) { 392 return res; 393 } 394 xsprintf(prompt,"[%016llX]: ",q); 395 break; 396 } 397 398 console_readline(prompt,line,sizeof(line)); 399 if (line[0] == '-') { 400 prev_addr -= wlen; 401 continue; 402 } 403 if (line[0] == '=') { 404 dumpmem(prev_addr,prev_addr,16,wlen); 405 continue; 406 } 407 if (line[0] == '.') { 408 break; 409 } 410 if (line[0] == '\0') { 411 prev_addr += wlen; 412 continue; 413 } 414 count = stuffmem(addr,wlen,line); 415 if (count < 0) return count; 416 if (count == 0) break; 417 prev_addr += count*wlen; 418 } 419 } 420 421 return 0; 422} 423 424static int ui_cmd_memfill(ui_cmdline_t *cmd,int argc,char *argv[]) 425{ 426 hsaddr_t addr; 427 char *atext; 428 int wlen; 429 int idx = 2; 430 int len; 431 uint64_t pattern; 432 int res; 433 434 getaddrargs(cmd,&prev_wtype,&prev_addr,&len); 435 436 atext = cmd_getarg(cmd,idx++); 437 if (!atext) return ui_showusage(cmd); 438 pattern = xtoq(atext); 439 440 addr = prev_addr; 441 442 if ((prev_wtype & ATYPE_TYPE_MASK) == ATYPE_TYPE_PHYS) { 443 addr = UNCADDR(addr); 444 } 445 446 wlen = prev_wtype & ATYPE_SIZE_MASK; 447 448 switch (wlen) { 449 case 1: 450 while (len > 0) { 451 if ((res = mem_poke(addr, pattern, MEM_BYTE))) { 452 /*Did not edit*/ 453 return 0; 454 } 455 addr++; 456 len--; 457 } 458 break; 459 case 2: 460 while (len > 0) { 461 if ((res = mem_poke(addr, pattern, MEM_HALFWORD))) { 462 return 0; 463 } 464 addr += 2; 465 len--; 466 } 467 break; 468 case 4: 469 while (len > 0) { 470 if ((res = mem_poke(addr, pattern, MEM_WORD))) { 471 return -1; 472 } 473 addr += 4; 474 len--; 475 } 476 break; 477 case 8: 478 while (len > 0) { 479 if ((res = mem_poke(addr, pattern, MEM_QUADWORD))) { 480 return 0; 481 } 482 addr += 8; 483 len--; 484 } 485 break; 486 } 487 488 return 0; 489} 490 491 492#if 1 493#define FILL(ptr,len,pattern) printf("Pattern: %016llX\n",pattern); \ 494 for (idx = 0; idx < len; idx+=wlen) hs_write64(ptr+idx,pattern) 495#define CHECK(ptr,len,pattern) for (idx = 0; idx < len; idx+=wlen) { \ 496 if (hs_read64(ptr+idx)!=pattern) {printf("Mismatch at %016llX: Expected %016llX got %016llX", \ 497 ptr+idx,pattern,hs_read64(ptr+idx)); \ 498 error = !nostop; loopmode = nostop;break;} \ 499 } 500 501#define MEMTEST(ptr,len,pattern) if (!error) { FILL(ptr,len,pattern) ; CHECK(ptr,len,pattern); } 502 503static int ui_cmd_memtest(ui_cmdline_t *cmd,int argc,char *argv[]) 504{ 505 hsaddr_t addr = 0; 506 int len = 0; 507 int wtype = 0; 508 hsaddr_t wlen; 509 int idx = 0; 510 int error = 0; 511 int loopmode = 0; 512 int pass =0; 513 int nostop; 514 515 nostop = cmd_sw_isset(cmd,"-nostop"); 516 517 getaddrargs(cmd,&wtype,&addr,&len); 518 519 wlen = 8; 520 addr &= ~(wlen-1); 521 522 if ((prev_wtype & ATYPE_TYPE_MASK) == ATYPE_TYPE_PHYS) { 523 addr = UNCADDR(addr); 524 } 525 526 if (cmd_sw_isset(cmd,"-loop")) { 527 loopmode = 1; 528 } 529 530 pass = 0; 531 for (;;) { 532 if (loopmode) { 533 printf("Pass %d\n",pass); 534 if (console_status()) break; 535 } 536 MEMTEST(addr,len,(idx*8)); 537 MEMTEST(addr,len, 0); 538 MEMTEST(addr,len,0xFFFFFFFFFFFFFFFFULL); 539 MEMTEST(addr,len,0x5555555555555555ULL); 540 MEMTEST(addr,len,0xAAAAAAAAAAAAAAAAULL); 541 MEMTEST(addr,len,0xFF00FF00FF00FF00ULL); 542 MEMTEST(addr,len,0x00FF00FF00FF00FFULL); 543 if (!loopmode) break; 544 pass++; 545 } 546 547 return 0; 548} 549#endif 550 551static int ui_cmd_memdump(ui_cmdline_t *cmd,int argc,char *argv[]) 552{ 553 hsaddr_t addr; 554 int res; 555 556 getaddrargs(cmd,&prev_wtype,&prev_addr,&prev_length); 557 558 addr = prev_addr; 559 if ((prev_wtype & ATYPE_TYPE_MASK) == ATYPE_TYPE_PHYS) { 560 addr = UNCADDR(addr); 561 } 562 563 res = dumpmem(addr, 564 prev_addr, 565 prev_length, 566 prev_wtype & ATYPE_SIZE_MASK); 567 568 if (res < 0) { 569 ui_showerror(res,"Could not display memory"); 570 } 571 else { 572 prev_addr += prev_length; 573 } 574 575 return res; 576} 577 578static int ui_cmd_disasm(ui_cmdline_t *cmd,int argc,char *argv[]) 579{ 580 hsaddr_t addr; 581 char buf[512]; 582 int idx; 583 uint32_t inst; 584 int res; 585 586 getaddrargs(cmd,&prev_wtype,&prev_addr,&prev_dlength); 587 588 prev_addr &= ~3; 589 590 addr = prev_addr; 591 if ((prev_wtype & ATYPE_TYPE_MASK) == ATYPE_TYPE_PHYS) { 592 addr = UNCADDR(addr); 593 } 594 595 for (idx = 0; idx < prev_dlength; idx++) { 596 if ((res = mem_peek(&inst, addr, MEM_WORD))) { 597 ui_showerror(res,"Could not disassemble memory"); 598 return res; 599 } 600 disasm_inst(buf,sizeof(buf),inst,(uint64_t) prev_addr); 601 xprintf("%P%c %08x %s\n",prev_addr,(addr != prev_addr) ? '%' : ':',inst,buf); 602 addr += 4; 603 prev_addr += 4; 604 } 605 606 return 0; 607} 608 609int ui_init_examcmds(void) 610{ 611 cmd_addcmd("u", 612 ui_cmd_disasm, 613 NULL, 614 "Disassemble instructions.", 615 "u [addr [length]]\n\n" 616 "This command disassembles instructions at the specified address.\n" 617 "CFE will display standard register names and symbolic names for\n" 618 "certain CP0 registers. The 'u' command remembers the last address\n" 619 "that was disassembled so you can enter 'u' again with no parameters\n" 620 "to continue a previous request.\n", 621 "-p;Address is an uncached physical address|" 622 "-v;Address is a kernel virtual address"); 623 624 625 cmd_addcmd("d", 626 ui_cmd_memdump, 627 NULL, 628 "Dump memory.", 629 "d [-b|-h|-w|-q] [addr [length]]\n\n" 630 "This command displays data from memory as bytes, halfwords, words,\n" 631 "or quadwords. ASCII text, if present, will appear to the right of\n" 632 "the hex data. The dump command remembers the previous word size,\n" 633 "dump length and last displayed address, so you can enter 'd' again\n" 634 "to continue a previous dump request.", 635 "-b;Dump memory as bytes|" 636 "-h;Dump memory as halfwords (16-bits)|" 637 "-w;Dump memory as words (32-bits)|" 638 "-q;Dump memory as quadwords (64-bits)|" 639 "-p;Address is an uncached physical address|" 640 "-v;Address is a kernel virtual address"); 641 642 643 cmd_addcmd("e", 644 ui_cmd_memedit, 645 NULL, 646 "Modify contents of memory.", 647 "e [-b|-h|-w|-q] [addr [data...]]\n\n" 648 "This command modifies the contents of memory. If you do not specify\n" 649 "data on the command line, CFE will prompt for it. When prompting for\n" 650 "data you may enter '-' to back up, '=' to dump memory at the current\n" 651 "location, or '.' to exit edit mode.", 652 "-b;Edit memory as bytes|" 653 "-h;Edit memory as halfwords (16-bits)|" 654 "-w;Edit memory as words (32-bits)|" 655 "-q;Edit memory as quadwords (64-bits)|" 656 "-p;Address is an uncached physical address|" 657 "-v;Address is a kernel virtual address"); 658 659 cmd_addcmd("f", 660 ui_cmd_memfill, 661 NULL, 662 "Fill contents of memory.", 663 "f [-b|-h|-w|-q] addr length pattern\n\n" 664 "This command modifies the contents of memory. You can specify the\n" 665 "starting address, length, and pattern of data to fill (in hex)\n", 666 "-b;Edit memory as bytes|" 667 "-h;Edit memory as halfwords (16-bits)|" 668 "-w;Edit memory as words (32-bits)|" 669 "-q;Edit memory as quadwords (64-bits)|" 670 "-p;Address is an uncached physical address|" 671 "-v;Address is a kernel virtual address"); 672 673#if 1 674 cmd_addcmd("memtest", 675 ui_cmd_memtest, 676 NULL, 677 "Test memory.", 678 "memtest [options] addr length\n\n" 679 "This command tests memory. It is a very crude test, so don't\n" 680 "rely on it for anything really important. Addr and length are in hex\n", 681 /* "-p;Address is an uncached physical address|" */ 682 "-v;Address is a kernel virtual address|" 683 "-nostop;Don't stop on error|" 684 "-loop;Loop till keypress"); 685#endif 686 687 688 prev_addr = PTR2HSADDR(KERNADDR(0)); 689 690 return 0; 691} 692 693 694 695 696 697 698 699 700 701 702 703