akaros/kern/src/monitor.c
<<
>>
Prefs
   1// Simple command-line kernel monitor useful for
   2// controlling the kernel and exploring the system interactively.
   3
   4#include <arch/arch.h>
   5#include <smp.h>
   6#include <arch/console.h>
   7
   8#include <stdio.h>
   9#include <string.h>
  10#include <assert.h>
  11#include <monitor.h>
  12#include <trap.h>
  13#include <pmap.h>
  14#include <kdebug.h>
  15#include <testing.h>
  16#include <manager.h>
  17#include <schedule.h>
  18#include <kdebug.h>
  19#include <syscall.h>
  20#include <kmalloc.h>
  21#include <elf.h>
  22#include <event.h>
  23#include <trap.h>
  24#include <time.h>
  25#include <percpu.h>
  26#include <kprof.h>
  27
  28#include <ros/memlayout.h>
  29#include <ros/event.h>
  30
  31#define CMDBUF_SIZE     80      // enough for one VGA text line
  32
  33typedef struct command {
  34        const char *name;
  35        const char *desc;
  36        // return -1 to force monitor to exit
  37        int (*func)(int argc, char **argv, struct hw_trapframe *hw_tf);
  38} command_t;
  39
  40static command_t commands[] = {
  41        { "help", "Display this list of commands", mon_help },
  42        { "kerninfo", "Display information about the kernel", mon_kerninfo },
  43        { "backtrace", "Dump a backtrace", mon_backtrace },
  44        { "bt", "Dump a backtrace", mon_backtrace },
  45        { "reboot", "Take a ride to the South Bay", mon_reboot },
  46        { "showmapping", "Shows VA->PA mappings", mon_showmapping},
  47        { "sm", "Shows VA->PA mappings", mon_sm},
  48        { "cpuinfo", "Prints CPU diagnostics", mon_cpuinfo},
  49        { "ps", "Prints process list", mon_ps},
  50        { "nanwan", "Meet Nanwan!!", mon_nanwan},
  51        { "bin_run", "Create and run a program from /bin", mon_bin_run},
  52        { "manager", "Run the manager", mon_manager},
  53        { "procinfo", "Show information about processes", mon_procinfo},
  54        { "pip", "Shorthand for procinfo pid", mon_pip},
  55        { "kill", "Kills a process", mon_kill},
  56        { "exit", "Leave the monitor", mon_exit},
  57        { "e", "Leave the monitor", mon_exit},
  58        { "kfunc", "Run a kernel function directly (!!!)", mon_kfunc},
  59        { "notify", "Notify a process.  Vcoreid will skip their prefs", mon_notify},
  60        { "measure", "Run a specific measurement", mon_measure},
  61        { "trace", "Run some tracing functions", mon_trace},
  62        { "monitor", "Run the monitor on another core", mon_monitor},
  63        { "sh", "Try to run a shell (bash)", mon_shell},
  64        { "bash", "Try to run a shell (bash)", mon_shell},
  65        { "bb", "Try to run a shell (bash)", mon_shell},
  66        { "alarm", "Alarm Diagnostics", mon_alarm},
  67        { "msr", "read/write msr: msr msr [value]", mon_msr},
  68        { "db", "Misc debugging", mon_db},
  69        { "px", "Toggle printx", mon_px},
  70        { "kpfret", "Attempt to idle after a kernel fault", mon_kpfret},
  71        { "ks", "Kernel scheduler hacks", mon_ks},
  72        { "coreinfo", "Print diagnostics for a core", mon_coreinfo},
  73        { "hexdump", "Hexdump PID's memory (0 for kernel)", mon_hexdump},
  74        { "hd", "Hexdump PID's memory (0 for kernel)", mon_hexdump},
  75        { "pahexdump", "Hexdump physical memory", mon_pahexdump},
  76        { "phd", "Hexdump physical memory", mon_pahexdump},
  77        { "dmesg", "Dump the dmesg buffer", mon_dmesg},
  78};
  79#define NCOMMANDS (sizeof(commands)/sizeof(commands[0]))
  80
  81/***** Implementations of basic kernel monitor commands *****/
  82
  83int mon_help(int argc, char **argv, struct hw_trapframe *hw_tf)
  84{
  85        int i;
  86
  87        for (i = 0; i < NCOMMANDS; i++)
  88                cprintf("%s - %s\n", commands[i].name, commands[i].desc);
  89        return 0;
  90}
  91
  92int mon_ps(int argc, char** argv, struct hw_trapframe *hw_tf)
  93{
  94        print_allpids();
  95        return 0;
  96}
  97
  98int mon_kerninfo(int argc, char **argv, struct hw_trapframe *hw_tf)
  99{
 100        extern char _start[], etext[], end[];
 101
 102        printk("Special kernel symbols:\n");
 103        printk("  _start %016x (virt)  %016x (phys)\n", _start,
 104               (uintptr_t)(_start - KERNBASE));
 105        printk("  etext  %016x (virt)  %016x (phys)\n", etext,
 106               (uintptr_t)(etext - KERNBASE));
 107        printk("  end    %016x (virt)  %016x (phys)\n", end,
 108               (uintptr_t)(end - KERNBASE));
 109        printk("Kernel executable memory footprint: %dKB\n",
 110               (uint32_t)(end-_start + 1023)/1024);
 111        return 0;
 112}
 113
 114static int __backtrace(int argc, char **argv, struct hw_trapframe *hw_tf)
 115{
 116        uintptr_t pc, fp;
 117
 118        if (argc == 1) {
 119                backtrace();
 120                return 0;
 121        }
 122        if (argc != 3) {
 123                printk("Need either no arguments, or two (PC and FP) in hex\n");
 124                return 1;
 125        }
 126        pc = strtol(argv[1], 0, 16);
 127        fp = strtol(argv[2], 0, 16);
 128        print_lock();
 129        printk("Backtrace from instruction %p, with frame pointer %p\n", pc,
 130               fp);
 131        backtrace_frame(pc, fp);
 132        print_unlock();
 133        return 0;
 134}
 135
 136int mon_backtrace(int argc, char **argv, struct hw_trapframe *hw_tf)
 137{
 138        return __backtrace(argc, argv, hw_tf);
 139}
 140
 141int mon_reboot(int argc, char **argv, struct hw_trapframe *hw_tf)
 142{
 143        cprintf("[Scottish Accent]: She's goin' down, Cap'n!\n");
 144        reboot();
 145
 146        // really, should never see this
 147        cprintf("Sigh....\n");
 148        return 0;
 149}
 150
 151static int __showmapping(int argc, char **argv, struct hw_trapframe *hw_tf)
 152{
 153        struct proc *p = NULL;
 154        uintptr_t start;
 155        size_t size;
 156        pgdir_t pgdir;
 157        pid_t pid;
 158
 159        if (argc < 3) {
 160                printk("Shows virt -> phys mappings for a virt addr range.\n");
 161                printk("Usage: showmapping PID START_ADDR [END_ADDR]\n");
 162                printk("    PID == 0 for the boot pgdir\n");
 163                return 1;
 164        }
 165        pid = strtol(argv[1], 0, 10);
 166        if (!pid) {
 167                pgdir = boot_pgdir;
 168        } else {
 169                p = pid2proc(pid);
 170                if (!p) {
 171                        printk("No proc with pid %d\n", pid);
 172                        return 1;
 173                }
 174                pgdir = p->env_pgdir;
 175        }
 176        start = ROUNDDOWN(strtol(argv[2], 0, 16), PGSIZE);
 177        size = (argc == 3) ? 1 : strtol(argv[3], 0, 16) - start;
 178        if (size/PGSIZE > 512) {
 179                cprintf("Not going to do this for more than 512 items\n");
 180                return 1;
 181        }
 182        show_mapping(pgdir, start, size);
 183        if (p)
 184                proc_decref(p);
 185        return 0;
 186}
 187
 188int mon_showmapping(int argc, char **argv, struct hw_trapframe *hw_tf)
 189{
 190        return __showmapping(argc, argv, hw_tf);
 191}
 192
 193int mon_sm(int argc, char **argv, struct hw_trapframe *hw_tf)
 194{
 195        return __showmapping(argc, argv, hw_tf);
 196}
 197
 198static void print_info_handler(struct hw_trapframe *hw_tf, void *data)
 199{
 200        uint64_t tsc = read_tsc();
 201
 202        print_lock();
 203        cprintf("----------------------------\n");
 204        cprintf("This is Core %d\n", core_id());
 205        cprintf("Timestamp = %lld\n", tsc);
 206#ifdef CONFIG_X86
 207        cprintf("Hardware core %d\n", hw_core_id());
 208        cprintf("MTRR_DEF_TYPE = 0x%08x\n", read_msr(IA32_MTRR_DEF_TYPE));
 209        cprintf("MTRR Phys0 Base = 0x%016llx, Mask = 0x%016llx\n",
 210                read_msr(0x200), read_msr(0x201));
 211        cprintf("MTRR Phys1 Base = 0x%016llx, Mask = 0x%016llx\n",
 212                read_msr(0x202), read_msr(0x203));
 213        cprintf("MTRR Phys2 Base = 0x%016llx, Mask = 0x%016llx\n",
 214                read_msr(0x204), read_msr(0x205));
 215        cprintf("MTRR Phys3 Base = 0x%016llx, Mask = 0x%016llx\n",
 216                read_msr(0x206), read_msr(0x207));
 217        cprintf("MTRR Phys4 Base = 0x%016llx, Mask = 0x%016llx\n",
 218                read_msr(0x208), read_msr(0x209));
 219        cprintf("MTRR Phys5 Base = 0x%016llx, Mask = 0x%016llx\n",
 220                read_msr(0x20a), read_msr(0x20b));
 221        cprintf("MTRR Phys6 Base = 0x%016llx, Mask = 0x%016llx\n",
 222                read_msr(0x20c), read_msr(0x20d));
 223        cprintf("MTRR Phys7 Base = 0x%016llx, Mask = 0x%016llx\n",
 224                read_msr(0x20e), read_msr(0x20f));
 225#endif // CONFIG_X86
 226        cprintf("----------------------------\n");
 227        print_unlock();
 228}
 229
 230static bool print_all_info(void)
 231{
 232        cprintf("\nCORE 0 asking all cores to print info:\n");
 233        smp_call_function_all(print_info_handler, NULL, 0);
 234        cprintf("\nDone!\n");
 235        return true;
 236}
 237
 238int mon_cpuinfo(int argc, char **argv, struct hw_trapframe *hw_tf)
 239{
 240        cprintf("Number of Cores detected: %d\n", num_cores);
 241        cprintf("Calling CPU's ID: 0x%08x\n", core_id());
 242
 243        if (argc < 2)
 244                smp_call_function_self(print_info_handler, NULL, 0);
 245        else
 246                smp_call_function_single(strtol(argv[1], 0, 10),
 247                                         print_info_handler, NULL, 0);
 248        return 0;
 249}
 250
 251int mon_manager(int argc, char** argv, struct hw_trapframe *hw_tf)
 252{
 253        manager();
 254        panic("should never get here");
 255        return 0;
 256}
 257
 258int mon_nanwan(int argc, char **argv, struct hw_trapframe *hw_tf)
 259{
 260        /* Borrowed with love from http://www.geocities.com/SoHo/7373/zoo.htm
 261         * (http://www.ascii-art.com/).  Slightly modified to make it 25 lines
 262         * tall. */
 263        print_lock();
 264        printk("\n");
 265        printk("             .-.  .-.\n");
 266        printk("             |  \\/  |\n");
 267        printk("            /,   ,_  `'-.\n");
 268        printk("          .-|\\   /`\\     '. \n");
 269        printk("        .'  0/   | 0\\  \\_  `\".  \n");
 270        printk("     .-'  _,/    '--'.'|#''---'\n");
 271        printk("      `--'  |       /   \\#\n");
 272        printk("            |      /     \\#\n");
 273        printk("            \\     ;|\\    .\\#\n");
 274        printk("            |' ' //  \\   ::\\# \n");
 275        printk("            \\   /`    \\   ':\\#\n");
 276        printk("             `\"`       \\..   \\#\n");
 277        printk("                        \\::.  \\#\n");
 278        printk("                         \\::   \\#\n");
 279        printk("                          \\'  .:\\#\n");
 280        printk("                           \\  :::\\#\n");
 281        printk("                            \\  '::\\#\n");
 282        printk("                             \\     \\#\n");
 283        printk("                              \\:.   \\#\n");
 284        printk("                               \\::   \\#\n");
 285        printk("                                \\'   .\\#\n");
 286        printk("                             jgs \\   ::\\#\n");
 287        printk("                                  \\      \n");
 288        print_unlock();
 289        return 0;
 290}
 291
 292int mon_bin_run(int argc, char **argv, struct hw_trapframe *hw_tf)
 293{
 294        if (argc < 2) {
 295                printk("Usage: bin_run FILENAME\n");
 296                return 1;
 297        }
 298        struct file_or_chan *program;
 299        int retval = 0;
 300        char buf[5 + MAX_FILENAME_SZ + 1] = "/bin/";    /* /bin/ + max + \0 */
 301
 302        strlcpy(buf, "/bin/", sizeof(buf));
 303        if (strlcat(buf, argv[1], sizeof(buf)) > sizeof(buf)) {
 304                printk("Filename '%s' too long!\n", argv[1]);
 305                return 1;
 306        }
 307        program = foc_open(buf, O_EXEC | O_READ, 0);
 308        if (!program) {
 309                printk("No such program!\n");
 310                return 1;
 311        }
 312        char **p_argv = kmalloc(sizeof(char*) * argc, 0); /* bin_run's argc */
 313        for (int i = 0; i < argc - 1; i++)
 314                p_argv[i] = argv[i + 1];
 315        p_argv[argc - 1] = 0;
 316        /* super ugly: we need to stash current, so that proc_create doesn't
 317         * pick up on random processes running here and assuming they are the
 318         * parent */
 319        struct proc *old_cur = current;
 320        current = 0;
 321        struct proc *p = proc_create(program, p_argv, NULL);
 322        current = old_cur;
 323        kfree(p_argv);
 324        proc_wakeup(p);
 325        proc_decref(p); /* let go of the reference created in proc_create() */
 326        foc_decref(program);
 327        /* Make a scheduling decision.  You might not get the process you
 328         * created, in the event there are others floating around that are
 329         * runnable */
 330        run_scheduler();
 331        /* want to idle, so we un the process we just selected.  this is a bit
 332         * hackish, but so is the monitor. */
 333        smp_idle();
 334        assert(0);
 335        return 0;
 336}
 337
 338int mon_procinfo(int argc, char **argv, struct hw_trapframe *hw_tf)
 339{
 340        int verbosity = 0;
 341
 342        if (argc < 2) {
 343                printk("Usage: procinfo OPTION\n");
 344                printk("\tall: show all active pids\n");
 345                printk("\tpid NUM: show a lot of info for proc NUM\n");
 346                printk("\tunlock: unlock the lock for the ADDR (OMG!!!)\n");
 347                printk("\tkill NUM: destroy proc NUM\n");
 348                return 1;
 349        }
 350        if (!strcmp(argv[1], "all")) {
 351                print_allpids();
 352        } else if (!strcmp(argv[1], "pid")) {
 353                if (argc < 3) {
 354                        printk("Give me a pid number.\n");
 355                        return 1;
 356                }
 357                if (argc >= 4)
 358                        verbosity = strtol(argv[3], 0, 0);
 359                print_proc_info(strtol(argv[2], 0, 0), verbosity);
 360        } else if (!strcmp(argv[1], "unlock")) {
 361                if (argc != 3) {
 362                        printk("Gimme lock address!  Me want lock address!.\n");
 363                        return 1;
 364                }
 365                spinlock_t *lock = (spinlock_t*)strtol(argv[2], 0, 16);
 366                if (!lock) {
 367                        printk("Null address...\n");
 368                        return 1;
 369                }
 370                spin_unlock(lock);
 371        } else if (!strcmp(argv[1], "kill")) {
 372                if (argc != 3) {
 373                        printk("Give me a pid number.\n");
 374                        return 1;
 375                }
 376                struct proc *p = pid2proc(strtol(argv[2], 0, 0));
 377                if (!p) {
 378                        printk("No such proc\n");
 379                        return 1;
 380                }
 381                proc_destroy(p);
 382                proc_decref(p);
 383        } else {
 384                printk("Bad option\n");
 385                return 1;
 386        }
 387        return 0;
 388}
 389
 390int mon_pip(int argc, char **argv, struct hw_trapframe *hw_tf)
 391{
 392        int verbosity = 0;
 393
 394        if (argc < 2) {
 395                printk("Give me a pid number.\n");
 396                return 1;
 397        }
 398        if (argc >= 3)
 399                verbosity = strtol(argv[2], 0, 0);
 400        print_proc_info(strtol(argv[1], 0, 0), verbosity);
 401        return 0;
 402}
 403
 404int mon_kill(int argc, char **argv, struct hw_trapframe *hw_tf)
 405{
 406        struct proc *p;
 407
 408        if (argc < 2) {
 409                printk("Usage: kill PID\n");
 410                return 1;
 411        }
 412        p = pid2proc(strtol(argv[1], 0, 0));
 413        if (!p) {
 414                printk("No such proc\n");
 415                return 1;
 416        }
 417        p->exitcode = 1;        /* typical EXIT_FAILURE */
 418        proc_destroy(p);
 419        proc_decref(p);
 420        return 0;
 421}
 422
 423int mon_exit(int argc, char **argv, struct hw_trapframe *hw_tf)
 424{
 425        return -1;
 426}
 427
 428int mon_kfunc(int argc, char **argv, struct hw_trapframe *hw_tf)
 429{
 430        long ret;
 431        long (*func)(void *arg, ...);
 432
 433        if (argc < 2) {
 434                printk("Usage: kfunc FUNCTION [arg1] [arg2] [etc]\n");
 435                printk("Use 0x with hex arguments.  Can take 6 args.\n");
 436                return 1;
 437        }
 438        func = (void*)get_symbol_addr(argv[1]);
 439        if (!func) {
 440                printk("Function not found.\n");
 441                return 1;
 442        }
 443        /* Not elegant, but whatever.  maybe there's a better syntax, or we can
 444         * do it with asm magic. */
 445        switch (argc) {
 446        case 2: /* have to fake one arg */
 447                ret = func((void*)0);
 448                break;
 449        case 3: /* the real first arg */
 450                ret = func((void*)strtol(argv[2], 0, 0));
 451                break;
 452        case 4:
 453                ret = func((void*)strtol(argv[2], 0, 0),
 454                                  strtol(argv[3], 0, 0));
 455                break;
 456        case 5:
 457                ret = func((void*)strtol(argv[2], 0, 0),
 458                                  strtol(argv[3], 0, 0),
 459                                  strtol(argv[4], 0, 0));
 460                break;
 461        case 6:
 462                ret = func((void*)strtol(argv[2], 0, 0),
 463                                  strtol(argv[3], 0, 0),
 464                                  strtol(argv[4], 0, 0),
 465                                  strtol(argv[5], 0, 0));
 466                break;
 467        case 7:
 468                ret = func((void*)strtol(argv[2], 0, 0),
 469                                  strtol(argv[3], 0, 0),
 470                                  strtol(argv[4], 0, 0),
 471                                  strtol(argv[5], 0, 0),
 472                                  strtol(argv[6], 0, 0));
 473                break;
 474        case 8:
 475                ret = func((void*)strtol(argv[2], 0, 0),
 476                                  strtol(argv[3], 0, 0),
 477                                  strtol(argv[4], 0, 0),
 478                                  strtol(argv[5], 0, 0),
 479                                  strtol(argv[6], 0, 0),
 480                                  strtol(argv[7], 0, 0));
 481                break;
 482        default:
 483                printk("Bad number of arguments.\n");
 484                return -1;
 485        }
 486        printk("%s (might have) returned %p\n", argv[1], ret);
 487        return 0;
 488}
 489
 490/* Sending a vcoreid forces an event and an IPI/notification */
 491int mon_notify(int argc, char **argv, struct hw_trapframe *hw_tf)
 492{
 493        struct proc *p;
 494        uint32_t vcoreid;
 495        struct event_msg msg = {0};
 496
 497        if (argc < 3) {
 498                printk("Usage: notify PID NUM [VCOREID]\n");
 499                return 1;
 500        }
 501        p = pid2proc(strtol(argv[1], 0, 0));
 502        if (!p) {
 503                printk("No such proc\n");
 504                return 1;
 505        }
 506        msg.ev_type = strtol(argv[2], 0, 0);
 507        if (argc == 4) {
 508                vcoreid = strtol(argv[3], 0, 0);
 509                if (!proc_vcoreid_is_safe(p, vcoreid)) {
 510                        printk("Bad vcoreid %d\n", vcoreid);
 511                        proc_decref(p);
 512                        return -1;
 513                }
 514                /* This will go to the private mbox */
 515                post_vcore_event(p, &msg, vcoreid, EVENT_VCORE_PRIVATE);
 516                proc_notify(p, vcoreid);
 517        } else {
 518                /* o/w, try and do what they want */
 519                send_kernel_event(p, &msg, 0);
 520        }
 521        proc_decref(p);
 522        return 0;
 523}
 524
 525/* Micro-benchmarky Measurements.  This is really fragile code that probably
 526 * won't work perfectly, esp as the kernel evolves. */
 527int mon_measure(int argc, char **argv, struct hw_trapframe *hw_tf)
 528{
 529        uint64_t begin = 0, diff = 0;
 530        uint32_t end_refcnt = 0;
 531
 532        if (argc < 2) {
 533                printk("Usage: measure OPTION\n");
 534                printk("\tkill PID : kill proc PID\n");
 535                printk("\tpreempt PID : preempt proc PID (no delay)\n");
 536                printk("\tpreempt PID [pcore] : preempt PID's pcore (no delay)\n");
 537                printk("\tpreempt-warn PID : warn-preempt proc PID (pending)\n");
 538                printk("\tpreempt-warn PID [pcore] : warn-preempt proc PID's pcore\n");
 539                printk("\tpreempt-raw PID : raw-preempt proc PID\n");
 540                printk("\tpreempt-raw PID [pcore] : raw-preempt proc PID's pcore\n");
 541                return 1;
 542        }
 543        if (!strcmp(argv[1], "kill")) {
 544                if (argc < 3) {
 545                        printk("Give me a pid number.\n");
 546                        return 1;
 547                }
 548                struct proc *p = pid2proc(strtol(argv[2], 0, 0));
 549                if (!p) {
 550                        printk("No such proc\n");
 551                        return 1;
 552                }
 553                begin = start_timing();
 554#ifdef CONFIG_APPSERVER
 555                printk("Warning: inaccurate due to the appserver.\n");
 556                end_refcnt = kref_refcnt(&p->p_kref) - p->procinfo->num_vcores
 557                             - 1;
 558#endif /* CONFIG_APPSERVER */
 559                proc_destroy(p);
 560                proc_decref(p);
 561#ifdef CONFIG_APPSERVER
 562                /* Won't be that accurate, since it's not actually going through
 563                 * the __proc_free() path. */
 564                spin_on(kref_refcnt(&p->p_kref) != end_refcnt);
 565#else
 566                /* this is a little ghetto. it's not fully free yet, but we are
 567                 * also slowing it down by messing with it, esp with the busy
 568                 * waiting on a hyperthreaded core. */
 569                spin_on(p->env_cr3);
 570#endif /* CONFIG_APPSERVER */
 571                /* No noticeable difference using stop_timing instead of
 572                 * read_tsc() */
 573                diff = stop_timing(begin);
 574        } else if (!strcmp(argv[1], "preempt")) {
 575                if (argc < 3) {
 576                        printk("Give me a pid number.\n");
 577                        return 1;
 578                }
 579                struct proc *p = pid2proc(strtol(argv[2], 0, 0));
 580                if (!p) {
 581                        printk("No such proc\n");
 582                        return 1;
 583                }
 584                if (argc == 4) {
 585                        /* single core being preempted, warned but no delay */
 586                        uint32_t pcoreid = strtol(argv[3], 0, 0);
 587
 588                        begin = start_timing();
 589                        if (proc_preempt_core(p, pcoreid, 1000000)) {
 590                                __sched_put_idle_core(p, pcoreid);
 591                                /* done when unmapped (right before abandoning)
 592                                 * */
 593                                spin_on(p->procinfo->pcoremap[pcoreid].valid);
 594                        } else {
 595                                printk("Core %d was not mapped to proc\n",
 596                                       pcoreid);
 597                        }
 598                        diff = stop_timing(begin);
 599                } else {
 600                        /* preempt all cores, warned but no delay */
 601                        end_refcnt = kref_refcnt(&p->p_kref)
 602                                     - p->procinfo->num_vcores;
 603                        begin = start_timing();
 604                        proc_preempt_all(p, 1000000);
 605                        /* a little ghetto, implies no one is using p */
 606                        spin_on(kref_refcnt(&p->p_kref) != end_refcnt);
 607                        diff = stop_timing(begin);
 608                }
 609                proc_decref(p);
 610        } else if (!strcmp(argv[1], "preempt-warn")) {
 611                if (argc < 3) {
 612                        printk("Give me a pid number.\n");
 613                        return 1;
 614                }
 615                struct proc *p = pid2proc(strtol(argv[2], 0, 0));
 616
 617                if (!p) {
 618                        printk("No such proc\n");
 619                        return 1;
 620                }
 621                printk("if this hangs, then the process isn't responding.\n");
 622                if (argc == 4) {
 623                        /* single core being preempted-warned */
 624                        uint32_t pcoreid = strtol(argv[3], 0, 0);
 625
 626                        spin_lock(&p->proc_lock);
 627                        uint32_t vcoreid =
 628                                p->procinfo->pcoremap[pcoreid].vcoreid;
 629
 630                        if (!p->procinfo->pcoremap[pcoreid].valid) {
 631                                printk("Pick a mapped pcore\n");
 632                                spin_unlock(&p->proc_lock);
 633                                return 1;
 634                        }
 635                        begin = start_timing();
 636                        __proc_preempt_warn(p, vcoreid, 1000000); // 1 sec
 637                        spin_unlock(&p->proc_lock);
 638                        /* done when unmapped (right before abandoning) */
 639                        spin_on(p->procinfo->pcoremap[pcoreid].valid);
 640                        diff = stop_timing(begin);
 641                } else {
 642                        /* preempt-warn all cores */
 643                        printk("this won't work if they can't yield their last vcore, will stop at 1!\n");
 644                        spin_lock(&p->proc_lock);
 645                        begin = start_timing();
 646                        __proc_preempt_warnall(p, 1000000);
 647                        spin_unlock(&p->proc_lock);
 648                        /* target cores do the unmapping / changing of the
 649                         * num_vcores */
 650                        spin_on(p->procinfo->num_vcores > 1);
 651                        diff = stop_timing(begin);
 652                }
 653                proc_decref(p);
 654        } else if (!strcmp(argv[1], "preempt-raw")) {
 655                if (argc < 3) {
 656                        printk("Give me a pid number.\n");
 657                        return 1;
 658                }
 659                struct proc *p = pid2proc(strtol(argv[2], 0, 0));
 660                if (!p) {
 661                        printk("No such proc\n");
 662                        return 1;
 663                }
 664                if (argc == 4) {
 665                        /* single core preempted, no warning or waiting */
 666                        uint32_t pcoreid = strtol(argv[3], 0, 0);
 667
 668                        spin_lock(&p->proc_lock);
 669                        if (!p->procinfo->pcoremap[pcoreid].valid) {
 670                                printk("Pick a mapped pcore\n");
 671                                spin_unlock(&p->proc_lock);
 672                                return 1;
 673                        }
 674                        begin = start_timing();
 675                        __proc_preempt_core(p, pcoreid);
 676                        if (!p->procinfo->num_vcores)
 677                                __proc_set_state(p, PROC_RUNNABLE_M);
 678                        spin_unlock(&p->proc_lock);
 679                        /* ghetto, since the ksched should be calling all of
 680                         * this */
 681                        __sched_put_idle_core(p, pcoreid);
 682                        /* done when unmapped (right before abandoning) */
 683                        spin_on(p->procinfo->pcoremap[pcoreid].valid);
 684                        diff = stop_timing(begin);
 685                } else {
 686                        /* preempt all cores, no warning or waiting */
 687                        spin_lock(&p->proc_lock);
 688                        uint32_t pc_arr[p->procinfo->num_vcores];
 689                        uint32_t num_revoked;
 690
 691                        end_refcnt = kref_refcnt(&p->p_kref)
 692                                     - p->procinfo->num_vcores;
 693                        begin = start_timing();
 694                        num_revoked = __proc_preempt_all(p, pc_arr);
 695                        __proc_set_state(p, PROC_RUNNABLE_M);
 696                        spin_unlock(&p->proc_lock);
 697                        if (num_revoked)
 698                                __sched_put_idle_cores(p, pc_arr, num_revoked);
 699                        /* a little ghetto, implies no one else is using p */
 700                        spin_on(kref_refcnt(&p->p_kref) != end_refcnt);
 701                        diff = stop_timing(begin);
 702                }
 703                proc_decref(p);
 704        } else {
 705                printk("Bad option\n");
 706                return 1;
 707        }
 708        printk("[Tired Giraffe Accent] Took %llu usec (%llu nsec) to finish.\n",
 709               tsc2usec(diff), tsc2nsec(diff));
 710        return 0;
 711}
 712
 713static bool mon_verbose_trace = FALSE;
 714static DEFINE_PERCPU(bool, mon_nmi_trace);
 715
 716static void emit_hwtf_backtrace(struct hw_trapframe *hw_tf)
 717{
 718        if (mon_verbose_trace) {
 719                printk("\n");
 720                print_trapframe(hw_tf);
 721                backtrace_hwtf(hw_tf);
 722        }
 723        printk("Core %d is at %p (%s)\n", core_id(), get_hwtf_pc(hw_tf),
 724               get_fn_name(get_hwtf_pc(hw_tf)));
 725}
 726
 727static void emit_vmtf_backtrace(struct vm_trapframe *vm_tf)
 728{
 729        if (mon_verbose_trace) {
 730                printk("\n");
 731                print_vmtrapframe(vm_tf);
 732        }
 733        printk("Core %d is at %p\n", core_id(), get_vmtf_pc(vm_tf));
 734}
 735
 736/* This is dangerous and could cause a deadlock, since it runs in NMI context.
 737 * It's only for monitor debugging, so YMMV.  We pass the type since the kernel
 738 * doesn't deal in contexts (yet) */
 739void emit_monitor_backtrace(int type, void *tf)
 740{
 741        if (!PERCPU_VAR(mon_nmi_trace))
 742                return;
 743        /* To prevent a spew of output during a lot of perf NMIs, we'll turn off
 744         * the monitor output as soon as any NMI hits our core. */
 745        PERCPU_VAR(mon_nmi_trace) = FALSE;
 746        print_lock();
 747        if (type == ROS_HW_CTX)
 748                emit_hwtf_backtrace((struct hw_trapframe*)tf);
 749        else
 750                emit_vmtf_backtrace((struct vm_trapframe*)tf);
 751        print_kmsgs(core_id());
 752        print_unlock();
 753}
 754
 755
 756int mon_trace(int argc, char **argv, struct hw_trapframe *hw_tf)
 757{
 758        int core;
 759        if (argc < 2) {
 760                printk("Usage: trace OPTION\n");
 761                printk("\tsyscall start [silent (0 or non-zero, NOT the word silent)] [pid]: starts tracing\n");
 762                printk("\tsyscall stop: stops tracing.\n");
 763                printk("\tcoretf COREID: prints PC, -1 for all cores, verbose => TF\n");
 764                printk("\tpcpui [type [coreid]]: runs pcpui trace ring handlers\n");
 765                printk("\tpcpui-reset [noclear]: resets/clears pcpui trace ring\n");
 766                printk("\tverbose: toggles verbosity, depends on trace command\n");
 767                return 1;
 768        }
 769        if (!strcmp(argv[1], "syscall")) {
 770                if (argc < 3) {
 771                        printk("Need a start or stop.\n");
 772                        return 1;
 773                }
 774                if (!strcmp(argv[2], "start")) {
 775                        systrace_loud = TRUE;
 776                } else if (!strcmp(argv[2], "stop")) {
 777                        systrace_loud = FALSE;
 778                } else {
 779                        printk("Need a start or stop.\n");
 780                        return 1;
 781                }
 782        } else if (!strcmp(argv[1], "coretf")) {
 783                if (argc != 3) {
 784                        printk("Need a coreid, fool.\n");
 785                        return 1;
 786                }
 787                core = strtol(argv[2], 0, 0);
 788                if (core < 0) {
 789                        printk("Sending NMIs to all cores:\n");
 790                        for (int i = 0; i < num_cores; i++) {
 791                                _PERCPU_VAR(mon_nmi_trace, i) = TRUE;
 792                                send_nmi(i);
 793                                udelay(1000000);
 794                        }
 795                } else {
 796                        printk("Sending NMI core %d:\n", core);
 797                        if (core >= num_cores) {
 798                                printk("No such core!  Maybe it's in another cell...\n");
 799                                return 1;
 800                        }
 801                        _PERCPU_VAR(mon_nmi_trace, core) = TRUE;
 802                        send_nmi(core);
 803                }
 804                udelay(1000000);
 805        } else if (!strcmp(argv[1], "pcpui")) {
 806                int pcpui_type, pcpui_coreid;
 807
 808                if (argc >= 3)
 809                        pcpui_type = strtol(argv[2], 0, 0);
 810                else
 811                        pcpui_type = 0;
 812                printk("\nRunning PCPUI Trace Ring handlers for type %d\n",
 813                       pcpui_type);
 814                if (argc >= 4) {
 815                        pcpui_coreid = strtol(argv[3], 0, 0);
 816                        pcpui_tr_foreach(pcpui_coreid, pcpui_type);
 817                } else {
 818                        pcpui_tr_foreach_all(pcpui_type);
 819                }
 820        } else if (!strcmp(argv[1], "pcpui-reset")) {
 821                if (argc >= 3) {
 822                        printk("\nResetting all PCPUI Trace Rings\n");
 823                        pcpui_tr_reset_all();
 824                } else {
 825                        printk("\nResetting/clearing all PCPUI Trace Rings\n");
 826                        pcpui_tr_reset_and_clear_all();
 827                }
 828        } else if (!strcmp(argv[1], "verbose")) {
 829                if (mon_verbose_trace) {
 830                        printk("Turning trace verbosity off\n");
 831                        mon_verbose_trace = FALSE;
 832                } else {
 833                        printk("Turning trace verbosity on\n");
 834                        mon_verbose_trace = TRUE;
 835                }
 836        } else if (!strcmp(argv[1], "opt2")) {
 837                if (argc != 3) {
 838                        printk("ERRRRRRRRRR.\n");
 839                        return 1;
 840                }
 841                print_proc_info(strtol(argv[2], 0, 0), 0);
 842        } else {
 843                printk("Bad option\n");
 844                return 1;
 845        }
 846        return 0;
 847}
 848
 849int mon_monitor(int argc, char **argv, struct hw_trapframe *hw_tf)
 850{
 851        if (argc < 2) {
 852                printk("Usage: monitor COREID\n");
 853                return 1;
 854        }
 855        uint32_t core = strtol(argv[1], 0, 0);
 856        if (core >= num_cores) {
 857                printk("No such core!  Maybe it's in another cell...\n");
 858                return 1;
 859        }
 860        send_kernel_message(core, __run_mon, 0, 0, 0, KMSG_ROUTINE);
 861        return 0;
 862}
 863
 864/***** Kernel monitor command interpreter *****/
 865
 866#define WHITESPACE "\t\r\n "
 867#define MAXARGS 16
 868
 869
 870int onecmd(int argc, char *argv[], struct hw_trapframe *hw_tf) {
 871        int i;
 872        if (!argc)
 873                return -1;
 874        for (i = 0; i < NCOMMANDS; i++) {
 875                if (strcmp(argv[0], commands[i].name) == 0)
 876                        return commands[i].func(argc, argv, hw_tf);
 877        }
 878        return -1;
 879}
 880
 881void __run_mon(uint32_t srcid, long a0, long a1, long a2)
 882{
 883        monitor(0);
 884}
 885
 886static int runcmd(char *real_buf, struct hw_trapframe *hw_tf) {
 887        char * buf = real_buf;
 888        int argc;
 889        char *argv[MAXARGS];
 890        int i;
 891
 892        // Parse the command buffer into whitespace-separated arguments
 893        argc = 0;
 894        argv[argc] = 0;
 895        /* Discard initial 'm ', which is a common mistake when using 'm' a lot
 896         */
 897        if ((buf[0] == 'm') && (buf[1] == ' '))
 898                buf += 2;
 899        while (1) {
 900                // gobble whitespace
 901                while (*buf && strchr(WHITESPACE, *buf))
 902                        *buf++ = 0;
 903                if (*buf == 0)
 904                        break;
 905
 906                // save and scan past next arg
 907                if (argc == MAXARGS-1) {
 908                        cprintf("Too many arguments (max %d)\n", MAXARGS);
 909                        return 0;
 910                }
 911                //This will get fucked at runtime..... in the ASS
 912                argv[argc++] = buf;
 913                while (*buf && !strchr(WHITESPACE, *buf))
 914                        buf++;
 915        }
 916        argv[argc] = 0;
 917
 918        // Lookup and invoke the command
 919        if (argc == 0)
 920                return 0;
 921        for (i = 0; i < NCOMMANDS; i++) {
 922                if (strcmp(argv[0], commands[i].name) == 0)
 923                        return commands[i].func(argc, argv, hw_tf);
 924        }
 925        cprintf("Unknown command '%s'\n", argv[0]);
 926        return 0;
 927}
 928
 929void monitor(struct hw_trapframe *hw_tf)
 930{
 931        #define MON_CMD_LENGTH 256
 932        char buf[MON_CMD_LENGTH];
 933        int cnt;
 934        int coreid = core_id_early();
 935
 936        /* they are always disabled, since we have this irqsave lock */
 937        if (irq_is_enabled())
 938                printk("Entering Nanwan's Dungeon on Core %d (Ints on):\n",
 939                       coreid);
 940        else
 941                printk("Entering Nanwan's Dungeon on Core %d (Ints off):\n",
 942                       coreid);
 943        printk("Type 'help' for a list of commands.\n");
 944
 945        if (hw_tf != NULL)
 946                print_trapframe(hw_tf);
 947
 948        while (1) {
 949                /* on occasion, the kernel monitor can migrate (like if you run
 950                 * something that blocks / syncs and wakes up on another core)
 951                 */
 952                cmb();
 953                cnt = readline(buf, MON_CMD_LENGTH, "ROS(Core %d)> ",
 954                               core_id_early());
 955                if (cnt > 0) {
 956                        buf[cnt] = 0;
 957                        if (runcmd(buf, hw_tf) < 0)
 958                                break;
 959                }
 960        }
 961}
 962
 963int mon_shell(int argc, char **argv, struct hw_trapframe *hw_tf)
 964{
 965        char *l_argv[2] = {"/bin/bash", "bash"};
 966        return mon_bin_run(2, l_argv, hw_tf);
 967}
 968
 969int mon_alarm(int argc, char **argv, struct hw_trapframe *hw_tf)
 970{
 971        if (argc < 2) {
 972                printk("Usage: alarm OPTION\n");
 973                printk("\tpcpu: print full alarm tchains from every core\n");
 974                return 1;
 975        }
 976        if (!strcmp(argv[1], "pcpu")) {
 977                print_pcpu_chains();
 978        } else {
 979                printk("Bad option\n");
 980                return 1;
 981        }
 982        return 0;
 983}
 984
 985static void show_msr(struct hw_trapframe *unused, void *v)
 986{
 987        int core = core_id();
 988        uint64_t val;
 989        uint32_t msr = *(uint32_t *)v;
 990
 991        val = read_msr(msr);
 992        printk("%d: %08x: %016llx\n", core, msr, val);
 993}
 994
 995struct set {
 996        uint32_t msr;
 997        uint64_t val;
 998};
 999
1000static void set_msr(struct hw_trapframe *unused, void *v)
1001{
1002        int core = core_id();
1003        struct set *s = v;
1004        uint32_t msr = s->msr;
1005        uint64_t val = s->val;
1006
1007        write_msr(msr, val);
1008        val = read_msr(msr);
1009        printk("%d: %08x: %016llx\n", core, msr, val);
1010}
1011
1012int mon_msr(int argc, char **argv, struct hw_trapframe *hw_tf)
1013{
1014#ifndef CONFIG_X86
1015        cprintf("Not on this architecture\n");
1016        return 1;
1017#else
1018        uint64_t val;
1019        uint32_t msr;
1020
1021        if (argc < 2 || argc > 3) {
1022                printk("Usage: msr register [value]\n");
1023                return 1;
1024        }
1025        msr = strtoul(argv[1], 0, 16);
1026        handler_wrapper_t *w;
1027        smp_call_function_all(show_msr, &msr, &w);
1028        smp_call_wait(w);
1029
1030        if (argc < 3)
1031                return 0;
1032        /* somewhat bogus on 32 bit. */
1033        val = strtoul(argv[2], 0, 16);
1034
1035        struct set set;
1036        set.msr = msr;
1037        set.val = val;
1038        smp_call_function_all(set_msr, &set, &w);
1039        smp_call_wait(w);
1040        return 0;
1041#endif
1042}
1043
1044int mon_db(int argc, char **argv, struct hw_trapframe *hw_tf)
1045{
1046        pid_t pid = -1;
1047
1048        if (argc < 2) {
1049                printk("Usage: db OPTION\n");
1050                printk("\tblk [PID]: print all blocked kthreads\n");
1051                printk("\taddr PID 0xADDR: lookup ADDR's file/vmr info\n");
1052                printk("\trv WAITER: backtrace rendez alarm waiter\n");
1053                return 1;
1054        }
1055        if (!strcmp(argv[1], "blk") || !strcmp(argv[1], "sem")) {
1056                if (argc > 2)
1057                        pid = strtol(argv[2], 0, 0);
1058                print_db_blk_info(pid);
1059        } else if (!strcmp(argv[1], "addr")) {
1060                if (argc < 4) {
1061                        printk("Usage: db addr PID 0xADDR\n");
1062                        return 1;
1063                }
1064                debug_addr_pid(strtol(argv[2], 0, 10), strtol(argv[3], 0, 16));
1065        } else if (!strcmp(argv[1], "rv")) {
1066                if (argc < 3) {
1067                        printk("Usage: db rv 0xWAITER\n");
1068                        return 1;
1069                }
1070                rendez_debug_waiter((struct alarm_waiter*)strtoul(argv[2], 0,
1071                                                                  16));
1072        } else {
1073                printk("Bad option\n");
1074                return 1;
1075        }
1076        return 0;
1077}
1078
1079int mon_px(int argc, char **argv, struct hw_trapframe *hw_tf)
1080{
1081        pid_t pid = 0;
1082        struct proc *p;
1083
1084        if (argc == 2)
1085                pid = strtol(argv[1], 0, 0);
1086        if (!pid) {
1087                set_printx(2);
1088                printk("Printxing is now %sabled\n", printx_on ? "en" : "dis");
1089                return 0;
1090        }
1091        p = pid2proc(pid);
1092        if (!p) {
1093                printk("No proc with pid %d\n", pid);
1094                return 1;
1095        }
1096        p->procdata->printx_on = !p->procdata->printx_on;
1097        proc_decref(p);
1098        return 0;
1099}
1100
1101/* Super hack.  Given a kernel hw_tf, we hack the RIP to smp_idle, then return
1102 * to it.  Any locks or other stuff being done is completely lost, so you could
1103 * deadlock.  This gets out of the "we're totall screwed, but don't want to
1104 * reboot right now", typically caused by screw-ups from the monitor. */
1105int mon_kpfret(int argc, char **argv, struct hw_trapframe *hw_tf)
1106{
1107        struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
1108
1109        /* if monitor had a TF, try to use that */
1110        if (!hw_tf) {
1111                if (argc < 2) {
1112                        printk("Usage: kpfret HW_TF\n");
1113                        return 1;
1114                }
1115                /* the hw_tf passed in is the one we got from monitor, which is
1116                 * 0 from panics. */
1117                hw_tf = (struct hw_trapframe*)strtol(argv[1], 0, 16);
1118        }
1119
1120        if (!in_kernel(hw_tf)) {
1121                printk("hw_tf %p was not a kernel tf!\n", hw_tf);
1122                return -1;
1123        }
1124
1125#ifdef CONFIG_X86
1126        hw_tf->tf_rip = (uintptr_t)smp_idle;
1127        dec_ktrap_depth(pcpui);
1128
1129        asm volatile("mov %0, %%rsp;"
1130                     "addq $0x10, %%rsp;"
1131                     "popq %%rax;"
1132                     "popq %%rbx;"
1133                     "popq %%rcx;"
1134                     "popq %%rdx;"
1135                     "popq %%rbp;"
1136                     "popq %%rsi;"
1137                     "popq %%rdi;"
1138                     "popq %%r8;"
1139                     "popq %%r9;"
1140                     "popq %%r10;"
1141                     "popq %%r11;"
1142                     "popq %%r12;"
1143                     "popq %%r13;"
1144                     "popq %%r14;"
1145                     "popq %%r15;"
1146                     "addq $0x10, %%rsp;"
1147                     "iretq;"
1148                                 : : "r"(hw_tf));
1149        assert(0);
1150#else
1151        printk("KPF return not supported\n");
1152        return -1;
1153#endif /* CONFIG_X86 */
1154}
1155
1156int mon_ks(int argc, char **argv, struct hw_trapframe *hw_tf)
1157{
1158        if (argc < 2) {
1159usage:
1160                printk("Usage: ks OPTION\n");
1161                printk("\tidles: show idle core map\n");
1162                printk("\tdiag: scheduler diagnostic report\n");
1163                printk("\tresources: show resources wanted/granted for all procs\n");
1164                printk("\tsort: sorts the idlecoremap, 1..n\n");
1165                printk("\tnc PCOREID: sets the next CG core allocated\n");
1166                return 1;
1167        }
1168        if (!strcmp(argv[1], "idles")) {
1169                print_idle_core_map();
1170        } else if (!strcmp(argv[1], "diag")) {
1171                sched_diag();
1172        } else if (!strcmp(argv[1], "resources")) {
1173                print_all_resources();
1174        } else if (!strcmp(argv[1], "sort")) {
1175                sort_idle_cores();
1176        } else if (!strcmp(argv[1], "nc")) {
1177                if (argc != 3) {
1178                        printk("Need a pcore number.\n");
1179                        return 1;
1180                }
1181                next_core_to_alloc(strtol(argv[2], 0, 0));
1182        } else {
1183                printk("Bad option %s\n", argv[1]);
1184                goto usage;
1185        }
1186        return 0;
1187}
1188
1189/* Prints info about a core.  Optional first arg == coreid. */
1190int mon_coreinfo(int argc, char **argv, struct hw_trapframe *hw_tf)
1191{
1192        struct per_cpu_info *pcpui;
1193        struct kthread *kth;
1194        int coreid = core_id();
1195
1196        if (argc >= 2)
1197                coreid = strtol(argv[1], 0, 0);
1198        pcpui = &per_cpu_info[coreid];
1199        printk("Core %d:\n\tcur_proc %d\n\towning proc %d, owning vc %d\n",
1200               coreid, pcpui->cur_proc ? pcpui->cur_proc->pid : 0,
1201               pcpui->owning_proc ? pcpui->owning_proc->pid : 0,
1202               pcpui->owning_vcoreid != 0xdeadbeef ? pcpui->owning_vcoreid : 0);
1203        kth = pcpui->cur_kthread;
1204        if (kth) {
1205                /* kth->proc is only used when the kthread is sleeping.  when
1206                 * it's running, we care about cur_proc.  if we're here, proc
1207                 * should be 0 unless the kth is concurrently sleeping (we
1208                 * called this remotely) */
1209                printk("\tkthread %p (%s), sysc %p (%d)\n", kth, kth->name,
1210                       kth->sysc, kth->sysc ? kth->sysc->num : -1);
1211        } else {
1212                /* Can happen during early boot */
1213                printk("\tNo kthread!\n");
1214        }
1215        return 0;
1216}
1217
1218int mon_hexdump(int argc, char **argv, struct hw_trapframe *hw_tf)
1219{
1220        struct proc *p = NULL;
1221        uintptr_t switch_state;
1222        pid_t pid;
1223        uintptr_t start;
1224        size_t len;
1225
1226        assert(argc >= 1);
1227        if (argc < 4) {
1228                printk("Usage: %s PID ADDR LEN\n", argv[0]);
1229                printk("    PID == 0 for kernel / don't care\n");
1230                return 1;
1231        }
1232        pid = strtol(argv[1], 0, 0);
1233        start = strtoul(argv[2], 0, 0);
1234        len = strtoul(argv[3], 0, 0);
1235        if (pid) {
1236                p = pid2proc(pid);
1237                if (!p) {
1238                        printk("No proc with pid %d\n", pid);
1239                        return 1;
1240                }
1241                switch_state = switch_to(p);
1242        }
1243        hexdump((void*)start, len);
1244        if (p) {
1245                switch_back(p, switch_state);
1246                proc_decref(p);
1247        }
1248        return 0;
1249}
1250
1251int mon_pahexdump(int argc, char **argv, struct hw_trapframe *hw_tf)
1252{
1253        uintptr_t start;
1254        size_t len;
1255
1256        assert(argc >= 1);
1257        if (argc < 3) {
1258                printk("Usage: %s PHYS_ADDR LEN\n", argv[0]);
1259                return 1;
1260        }
1261        start = strtoul(argv[1], 0, 0);
1262        len = strtoul(argv[2], 0, 0);
1263        pahexdump(start, len);
1264        return 0;
1265}
1266
1267int mon_dmesg(int argc, char **argv, struct hw_trapframe *hw_tf)
1268{
1269        kprof_dump_data();
1270        return 0;
1271}
1272