|  | // Simple command-line kernel monitor useful for | 
|  | // controlling the kernel and exploring the system interactively. | 
|  |  | 
|  | #include <arch/arch.h> | 
|  | #include <smp.h> | 
|  | #include <arch/console.h> | 
|  |  | 
|  | #include <stdio.h> | 
|  | #include <string.h> | 
|  | #include <assert.h> | 
|  | #include <monitor.h> | 
|  | #include <trap.h> | 
|  | #include <pmap.h> | 
|  | #include <kdebug.h> | 
|  | #include <testing.h> | 
|  | #include <manager.h> | 
|  | #include <schedule.h> | 
|  | #include <kdebug.h> | 
|  | #include <syscall.h> | 
|  | #include <kmalloc.h> | 
|  | #include <elf.h> | 
|  | #include <event.h> | 
|  | #include <trap.h> | 
|  | #include <time.h> | 
|  | #include <percpu.h> | 
|  | #include <kprof.h> | 
|  |  | 
|  | #include <ros/memlayout.h> | 
|  | #include <ros/event.h> | 
|  |  | 
|  | #define CMDBUF_SIZE	80	// enough for one VGA text line | 
|  |  | 
|  | typedef struct command { | 
|  | const char *name; | 
|  | const char *desc; | 
|  | // return -1 to force monitor to exit | 
|  | int (*func)(int argc, char **argv, struct hw_trapframe *hw_tf); | 
|  | } command_t; | 
|  |  | 
|  | static command_t commands[] = { | 
|  | { "help", "Display this list of commands", mon_help }, | 
|  | { "kerninfo", "Display information about the kernel", mon_kerninfo }, | 
|  | { "backtrace", "Dump a backtrace", mon_backtrace }, | 
|  | { "bt", "Dump a backtrace", mon_backtrace }, | 
|  | { "reboot", "Take a ride to the South Bay", mon_reboot }, | 
|  | { "showmapping", "Shows VA->PA mappings", mon_showmapping}, | 
|  | { "sm", "Shows VA->PA mappings", mon_sm}, | 
|  | { "cpuinfo", "Prints CPU diagnostics", mon_cpuinfo}, | 
|  | { "ps", "Prints process list", mon_ps}, | 
|  | { "nanwan", "Meet Nanwan!!", mon_nanwan}, | 
|  | { "bin_run", "Create and run a program from /bin", mon_bin_run}, | 
|  | { "manager", "Run the manager", mon_manager}, | 
|  | { "procinfo", "Show information about processes", mon_procinfo}, | 
|  | { "pip", "Shorthand for procinfo pid", mon_pip}, | 
|  | { "kill", "Kills a process", mon_kill}, | 
|  | { "exit", "Leave the monitor", mon_exit}, | 
|  | { "e", "Leave the monitor", mon_exit}, | 
|  | { "kfunc", "Run a kernel function directly (!!!)", mon_kfunc}, | 
|  | { "notify", "Notify a process.  Vcoreid will skip their prefs", mon_notify}, | 
|  | { "measure", "Run a specific measurement", mon_measure}, | 
|  | { "trace", "Run some tracing functions", mon_trace}, | 
|  | { "monitor", "Run the monitor on another core", mon_monitor}, | 
|  | { "sh", "Try to run a shell (bash)", mon_shell}, | 
|  | { "bash", "Try to run a shell (bash)", mon_shell}, | 
|  | { "bb", "Try to run a shell (bash)", mon_shell}, | 
|  | { "alarm", "Alarm Diagnostics", mon_alarm}, | 
|  | { "msr", "read/write msr: msr msr [value]", mon_msr}, | 
|  | { "db", "Misc debugging", mon_db}, | 
|  | { "px", "Toggle printx", mon_px}, | 
|  | { "kpfret", "Attempt to idle after a kernel fault", mon_kpfret}, | 
|  | { "ks", "Kernel scheduler hacks", mon_ks}, | 
|  | { "coreinfo", "Print diagnostics for a core", mon_coreinfo}, | 
|  | { "hexdump", "Hexdump PID's memory (0 for kernel)", mon_hexdump}, | 
|  | { "hd", "Hexdump PID's memory (0 for kernel)", mon_hexdump}, | 
|  | { "pahexdump", "Hexdump physical memory", mon_pahexdump}, | 
|  | { "phd", "Hexdump physical memory", mon_pahexdump}, | 
|  | { "dmesg", "Dump the dmesg buffer", mon_dmesg}, | 
|  | }; | 
|  | #define NCOMMANDS (sizeof(commands)/sizeof(commands[0])) | 
|  |  | 
|  | /***** Implementations of basic kernel monitor commands *****/ | 
|  |  | 
|  | int mon_help(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | for (i = 0; i < NCOMMANDS; i++) | 
|  | cprintf("%s - %s\n", commands[i].name, commands[i].desc); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int mon_ps(int argc, char** argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | print_allpids(); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int mon_kerninfo(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | extern char _start[], etext[], end[]; | 
|  |  | 
|  | printk("Special kernel symbols:\n"); | 
|  | printk("  _start %016x (virt)  %016x (phys)\n", _start, | 
|  | (uintptr_t)(_start - KERNBASE)); | 
|  | printk("  etext  %016x (virt)  %016x (phys)\n", etext, | 
|  | (uintptr_t)(etext - KERNBASE)); | 
|  | printk("  end    %016x (virt)  %016x (phys)\n", end, | 
|  | (uintptr_t)(end - KERNBASE)); | 
|  | printk("Kernel executable memory footprint: %dKB\n", | 
|  | (uint32_t)(end-_start + 1023)/1024); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int __backtrace(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | uintptr_t pc, fp; | 
|  |  | 
|  | if (argc == 1) { | 
|  | backtrace(); | 
|  | return 0; | 
|  | } | 
|  | if (argc != 3) { | 
|  | printk("Need either no arguments, or two (PC and FP) in hex\n"); | 
|  | return 1; | 
|  | } | 
|  | pc = strtol(argv[1], 0, 16); | 
|  | fp = strtol(argv[2], 0, 16); | 
|  | print_lock(); | 
|  | printk("Backtrace from instruction %p, with frame pointer %p\n", pc, | 
|  | fp); | 
|  | backtrace_frame(pc, fp); | 
|  | print_unlock(); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int mon_backtrace(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | return __backtrace(argc, argv, hw_tf); | 
|  | } | 
|  |  | 
|  | int mon_reboot(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | cprintf("[Scottish Accent]: She's goin' down, Cap'n!\n"); | 
|  | reboot(); | 
|  |  | 
|  | // really, should never see this | 
|  | cprintf("Sigh....\n"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int __showmapping(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | struct proc *p = NULL; | 
|  | uintptr_t start; | 
|  | size_t size; | 
|  | pgdir_t pgdir; | 
|  | pid_t pid; | 
|  |  | 
|  | if (argc < 3) { | 
|  | printk("Shows virt -> phys mappings for a virt addr range.\n"); | 
|  | printk("Usage: showmapping PID START_ADDR [END_ADDR]\n"); | 
|  | printk("    PID == 0 for the boot pgdir\n"); | 
|  | return 1; | 
|  | } | 
|  | pid = strtol(argv[1], 0, 10); | 
|  | if (!pid) { | 
|  | pgdir = boot_pgdir; | 
|  | } else { | 
|  | p = pid2proc(pid); | 
|  | if (!p) { | 
|  | printk("No proc with pid %d\n", pid); | 
|  | return 1; | 
|  | } | 
|  | pgdir = p->env_pgdir; | 
|  | } | 
|  | start = ROUNDDOWN(strtol(argv[2], 0, 16), PGSIZE); | 
|  | size = (argc == 3) ? 1 : strtol(argv[3], 0, 16) - start; | 
|  | if (size/PGSIZE > 512) { | 
|  | cprintf("Not going to do this for more than 512 items\n"); | 
|  | return 1; | 
|  | } | 
|  | show_mapping(pgdir, start, size); | 
|  | if (p) | 
|  | proc_decref(p); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int mon_showmapping(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | return __showmapping(argc, argv, hw_tf); | 
|  | } | 
|  |  | 
|  | int mon_sm(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | return __showmapping(argc, argv, hw_tf); | 
|  | } | 
|  |  | 
|  | static void print_info_handler(struct hw_trapframe *hw_tf, void *data) | 
|  | { | 
|  | uint64_t tsc = read_tsc(); | 
|  |  | 
|  | print_lock(); | 
|  | cprintf("----------------------------\n"); | 
|  | cprintf("This is Core %d\n", core_id()); | 
|  | cprintf("Timestamp = %lld\n", tsc); | 
|  | #ifdef CONFIG_X86 | 
|  | cprintf("Hardware core %d\n", hw_core_id()); | 
|  | cprintf("MTRR_DEF_TYPE = 0x%08x\n", read_msr(IA32_MTRR_DEF_TYPE)); | 
|  | cprintf("MTRR Phys0 Base = 0x%016llx, Mask = 0x%016llx\n", | 
|  | read_msr(0x200), read_msr(0x201)); | 
|  | cprintf("MTRR Phys1 Base = 0x%016llx, Mask = 0x%016llx\n", | 
|  | read_msr(0x202), read_msr(0x203)); | 
|  | cprintf("MTRR Phys2 Base = 0x%016llx, Mask = 0x%016llx\n", | 
|  | read_msr(0x204), read_msr(0x205)); | 
|  | cprintf("MTRR Phys3 Base = 0x%016llx, Mask = 0x%016llx\n", | 
|  | read_msr(0x206), read_msr(0x207)); | 
|  | cprintf("MTRR Phys4 Base = 0x%016llx, Mask = 0x%016llx\n", | 
|  | read_msr(0x208), read_msr(0x209)); | 
|  | cprintf("MTRR Phys5 Base = 0x%016llx, Mask = 0x%016llx\n", | 
|  | read_msr(0x20a), read_msr(0x20b)); | 
|  | cprintf("MTRR Phys6 Base = 0x%016llx, Mask = 0x%016llx\n", | 
|  | read_msr(0x20c), read_msr(0x20d)); | 
|  | cprintf("MTRR Phys7 Base = 0x%016llx, Mask = 0x%016llx\n", | 
|  | read_msr(0x20e), read_msr(0x20f)); | 
|  | #endif // CONFIG_X86 | 
|  | cprintf("----------------------------\n"); | 
|  | print_unlock(); | 
|  | } | 
|  |  | 
|  | static bool print_all_info(void) | 
|  | { | 
|  | cprintf("\nCORE 0 asking all cores to print info:\n"); | 
|  | smp_call_function_all(print_info_handler, NULL, 0); | 
|  | cprintf("\nDone!\n"); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | int mon_cpuinfo(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | cprintf("Number of Cores detected: %d\n", num_cores); | 
|  | cprintf("Calling CPU's ID: 0x%08x\n", core_id()); | 
|  |  | 
|  | if (argc < 2) | 
|  | smp_call_function_self(print_info_handler, NULL, 0); | 
|  | else | 
|  | smp_call_function_single(strtol(argv[1], 0, 10), | 
|  | print_info_handler, NULL, 0); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int mon_manager(int argc, char** argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | manager(); | 
|  | panic("should never get here"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int mon_nanwan(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | /* Borrowed with love from http://www.geocities.com/SoHo/7373/zoo.htm | 
|  | * (http://www.ascii-art.com/).  Slightly modified to make it 25 lines | 
|  | * tall. */ | 
|  | print_lock(); | 
|  | printk("\n"); | 
|  | printk("             .-.  .-.\n"); | 
|  | printk("             |  \\/  |\n"); | 
|  | printk("            /,   ,_  `'-.\n"); | 
|  | printk("          .-|\\   /`\\     '. \n"); | 
|  | printk("        .'  0/   | 0\\  \\_  `\".  \n"); | 
|  | printk("     .-'  _,/    '--'.'|#''---'\n"); | 
|  | printk("      `--'  |       /   \\#\n"); | 
|  | printk("            |      /     \\#\n"); | 
|  | printk("            \\     ;|\\    .\\#\n"); | 
|  | printk("            |' ' //  \\   ::\\# \n"); | 
|  | printk("            \\   /`    \\   ':\\#\n"); | 
|  | printk("             `\"`       \\..   \\#\n"); | 
|  | printk("                        \\::.  \\#\n"); | 
|  | printk("                         \\::   \\#\n"); | 
|  | printk("                          \\'  .:\\#\n"); | 
|  | printk("                           \\  :::\\#\n"); | 
|  | printk("                            \\  '::\\#\n"); | 
|  | printk("                             \\     \\#\n"); | 
|  | printk("                              \\:.   \\#\n"); | 
|  | printk("                               \\::   \\#\n"); | 
|  | printk("                                \\'   .\\#\n"); | 
|  | printk("                             jgs \\   ::\\#\n"); | 
|  | printk("                                  \\      \n"); | 
|  | print_unlock(); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int mon_bin_run(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | if (argc < 2) { | 
|  | printk("Usage: bin_run FILENAME\n"); | 
|  | return 1; | 
|  | } | 
|  | struct file_or_chan *program; | 
|  | int retval = 0; | 
|  | char buf[5 + MAX_FILENAME_SZ + 1] = "/bin/";	/* /bin/ + max + \0 */ | 
|  |  | 
|  | strlcpy(buf, "/bin/", sizeof(buf)); | 
|  | if (strlcat(buf, argv[1], sizeof(buf)) > sizeof(buf)) { | 
|  | printk("Filename '%s' too long!\n", argv[1]); | 
|  | return 1; | 
|  | } | 
|  | program = foc_open(buf, O_EXEC | O_READ, 0); | 
|  | if (!program) { | 
|  | printk("No such program!\n"); | 
|  | return 1; | 
|  | } | 
|  | char **p_argv = kmalloc(sizeof(char*) * argc, 0); /* bin_run's argc */ | 
|  | for (int i = 0; i < argc - 1; i++) | 
|  | p_argv[i] = argv[i + 1]; | 
|  | p_argv[argc - 1] = 0; | 
|  | /* super ugly: we need to stash current, so that proc_create doesn't | 
|  | * pick up on random processes running here and assuming they are the | 
|  | * parent */ | 
|  | struct proc *old_cur = current; | 
|  | current = 0; | 
|  | struct proc *p = proc_create(program, p_argv, NULL); | 
|  | current = old_cur; | 
|  | kfree(p_argv); | 
|  | proc_wakeup(p); | 
|  | proc_decref(p); /* let go of the reference created in proc_create() */ | 
|  | foc_decref(program); | 
|  | /* Make a scheduling decision.  You might not get the process you | 
|  | * created, in the event there are others floating around that are | 
|  | * runnable */ | 
|  | run_scheduler(); | 
|  | /* want to idle, so we un the process we just selected.  this is a bit | 
|  | * hackish, but so is the monitor. */ | 
|  | smp_idle(); | 
|  | assert(0); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int mon_procinfo(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | int verbosity = 0; | 
|  |  | 
|  | if (argc < 2) { | 
|  | printk("Usage: procinfo OPTION\n"); | 
|  | printk("\tall: show all active pids\n"); | 
|  | printk("\tpid NUM: show a lot of info for proc NUM\n"); | 
|  | printk("\tunlock: unlock the lock for the ADDR (OMG!!!)\n"); | 
|  | printk("\tkill NUM: destroy proc NUM\n"); | 
|  | return 1; | 
|  | } | 
|  | if (!strcmp(argv[1], "all")) { | 
|  | print_allpids(); | 
|  | } else if (!strcmp(argv[1], "pid")) { | 
|  | if (argc < 3) { | 
|  | printk("Give me a pid number.\n"); | 
|  | return 1; | 
|  | } | 
|  | if (argc >= 4) | 
|  | verbosity = strtol(argv[3], 0, 0); | 
|  | print_proc_info(strtol(argv[2], 0, 0), verbosity); | 
|  | } else if (!strcmp(argv[1], "unlock")) { | 
|  | if (argc != 3) { | 
|  | printk("Gimme lock address!  Me want lock address!.\n"); | 
|  | return 1; | 
|  | } | 
|  | spinlock_t *lock = (spinlock_t*)strtol(argv[2], 0, 16); | 
|  | if (!lock) { | 
|  | printk("Null address...\n"); | 
|  | return 1; | 
|  | } | 
|  | spin_unlock(lock); | 
|  | } else if (!strcmp(argv[1], "kill")) { | 
|  | if (argc != 3) { | 
|  | printk("Give me a pid number.\n"); | 
|  | return 1; | 
|  | } | 
|  | struct proc *p = pid2proc(strtol(argv[2], 0, 0)); | 
|  | if (!p) { | 
|  | printk("No such proc\n"); | 
|  | return 1; | 
|  | } | 
|  | proc_destroy(p); | 
|  | proc_decref(p); | 
|  | } else { | 
|  | printk("Bad option\n"); | 
|  | return 1; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int mon_pip(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | int verbosity = 0; | 
|  |  | 
|  | if (argc < 2) { | 
|  | printk("Give me a pid number.\n"); | 
|  | return 1; | 
|  | } | 
|  | if (argc >= 3) | 
|  | verbosity = strtol(argv[2], 0, 0); | 
|  | print_proc_info(strtol(argv[1], 0, 0), verbosity); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int mon_kill(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | struct proc *p; | 
|  |  | 
|  | if (argc < 2) { | 
|  | printk("Usage: kill PID\n"); | 
|  | return 1; | 
|  | } | 
|  | p = pid2proc(strtol(argv[1], 0, 0)); | 
|  | if (!p) { | 
|  | printk("No such proc\n"); | 
|  | return 1; | 
|  | } | 
|  | p->exitcode = 1;	/* typical EXIT_FAILURE */ | 
|  | proc_destroy(p); | 
|  | proc_decref(p); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int mon_exit(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | int mon_kfunc(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | long ret; | 
|  | long (*func)(void *arg, ...); | 
|  |  | 
|  | if (argc < 2) { | 
|  | printk("Usage: kfunc FUNCTION [arg1] [arg2] [etc]\n"); | 
|  | printk("Use 0x with hex arguments.  Can take 6 args.\n"); | 
|  | return 1; | 
|  | } | 
|  | func = (void*)get_symbol_addr(argv[1]); | 
|  | if (!func) { | 
|  | printk("Function not found.\n"); | 
|  | return 1; | 
|  | } | 
|  | /* Not elegant, but whatever.  maybe there's a better syntax, or we can | 
|  | * do it with asm magic. */ | 
|  | switch (argc) { | 
|  | case 2: /* have to fake one arg */ | 
|  | ret = func((void*)0); | 
|  | break; | 
|  | case 3: /* the real first arg */ | 
|  | ret = func((void*)strtol(argv[2], 0, 0)); | 
|  | break; | 
|  | case 4: | 
|  | ret = func((void*)strtol(argv[2], 0, 0), | 
|  | strtol(argv[3], 0, 0)); | 
|  | break; | 
|  | case 5: | 
|  | ret = func((void*)strtol(argv[2], 0, 0), | 
|  | strtol(argv[3], 0, 0), | 
|  | strtol(argv[4], 0, 0)); | 
|  | break; | 
|  | case 6: | 
|  | ret = func((void*)strtol(argv[2], 0, 0), | 
|  | strtol(argv[3], 0, 0), | 
|  | strtol(argv[4], 0, 0), | 
|  | strtol(argv[5], 0, 0)); | 
|  | break; | 
|  | case 7: | 
|  | ret = func((void*)strtol(argv[2], 0, 0), | 
|  | strtol(argv[3], 0, 0), | 
|  | strtol(argv[4], 0, 0), | 
|  | strtol(argv[5], 0, 0), | 
|  | strtol(argv[6], 0, 0)); | 
|  | break; | 
|  | case 8: | 
|  | ret = func((void*)strtol(argv[2], 0, 0), | 
|  | strtol(argv[3], 0, 0), | 
|  | strtol(argv[4], 0, 0), | 
|  | strtol(argv[5], 0, 0), | 
|  | strtol(argv[6], 0, 0), | 
|  | strtol(argv[7], 0, 0)); | 
|  | break; | 
|  | default: | 
|  | printk("Bad number of arguments.\n"); | 
|  | return -1; | 
|  | } | 
|  | printk("%s (might have) returned %p\n", argv[1], ret); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Sending a vcoreid forces an event and an IPI/notification */ | 
|  | int mon_notify(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | struct proc *p; | 
|  | uint32_t vcoreid; | 
|  | struct event_msg msg = {0}; | 
|  |  | 
|  | if (argc < 3) { | 
|  | printk("Usage: notify PID NUM [VCOREID]\n"); | 
|  | return 1; | 
|  | } | 
|  | p = pid2proc(strtol(argv[1], 0, 0)); | 
|  | if (!p) { | 
|  | printk("No such proc\n"); | 
|  | return 1; | 
|  | } | 
|  | msg.ev_type = strtol(argv[2], 0, 0); | 
|  | if (argc == 4) { | 
|  | vcoreid = strtol(argv[3], 0, 0); | 
|  | /* This will go to the private mbox */ | 
|  | post_vcore_event(p, &msg, vcoreid, EVENT_VCORE_PRIVATE); | 
|  | proc_notify(p, vcoreid); | 
|  | } else { | 
|  | /* o/w, try and do what they want */ | 
|  | send_kernel_event(p, &msg, 0); | 
|  | } | 
|  | proc_decref(p); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Micro-benchmarky Measurements.  This is really fragile code that probably | 
|  | * won't work perfectly, esp as the kernel evolves. */ | 
|  | int mon_measure(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | uint64_t begin = 0, diff = 0; | 
|  | uint32_t end_refcnt = 0; | 
|  |  | 
|  | if (argc < 2) { | 
|  | printk("Usage: measure OPTION\n"); | 
|  | printk("\tkill PID : kill proc PID\n"); | 
|  | printk("\tpreempt PID : preempt proc PID (no delay)\n"); | 
|  | printk("\tpreempt PID [pcore] : preempt PID's pcore (no delay)\n"); | 
|  | printk("\tpreempt-warn PID : warn-preempt proc PID (pending)\n"); | 
|  | printk("\tpreempt-warn PID [pcore] : warn-preempt proc PID's pcore\n"); | 
|  | printk("\tpreempt-raw PID : raw-preempt proc PID\n"); | 
|  | printk("\tpreempt-raw PID [pcore] : raw-preempt proc PID's pcore\n"); | 
|  | return 1; | 
|  | } | 
|  | if (!strcmp(argv[1], "kill")) { | 
|  | if (argc < 3) { | 
|  | printk("Give me a pid number.\n"); | 
|  | return 1; | 
|  | } | 
|  | struct proc *p = pid2proc(strtol(argv[2], 0, 0)); | 
|  | if (!p) { | 
|  | printk("No such proc\n"); | 
|  | return 1; | 
|  | } | 
|  | begin = start_timing(); | 
|  | #ifdef CONFIG_APPSERVER | 
|  | printk("Warning: inaccurate due to the appserver.\n"); | 
|  | end_refcnt = kref_refcnt(&p->p_kref) - p->procinfo->num_vcores | 
|  | - 1; | 
|  | #endif /* CONFIG_APPSERVER */ | 
|  | proc_destroy(p); | 
|  | proc_decref(p); | 
|  | #ifdef CONFIG_APPSERVER | 
|  | /* Won't be that accurate, since it's not actually going through | 
|  | * the __proc_free() path. */ | 
|  | spin_on(kref_refcnt(&p->p_kref) != end_refcnt); | 
|  | #else | 
|  | /* this is a little ghetto. it's not fully free yet, but we are | 
|  | * also slowing it down by messing with it, esp with the busy | 
|  | * waiting on a hyperthreaded core. */ | 
|  | spin_on(p->env_cr3); | 
|  | #endif /* CONFIG_APPSERVER */ | 
|  | /* No noticeable difference using stop_timing instead of | 
|  | * read_tsc() */ | 
|  | diff = stop_timing(begin); | 
|  | } else if (!strcmp(argv[1], "preempt")) { | 
|  | if (argc < 3) { | 
|  | printk("Give me a pid number.\n"); | 
|  | return 1; | 
|  | } | 
|  | struct proc *p = pid2proc(strtol(argv[2], 0, 0)); | 
|  | if (!p) { | 
|  | printk("No such proc\n"); | 
|  | return 1; | 
|  | } | 
|  | if (argc == 4) { | 
|  | /* single core being preempted, warned but no delay */ | 
|  | uint32_t pcoreid = strtol(argv[3], 0, 0); | 
|  |  | 
|  | begin = start_timing(); | 
|  | if (proc_preempt_core(p, pcoreid, 1000000)) { | 
|  | __sched_put_idle_core(p, pcoreid); | 
|  | /* done when unmapped (right before abandoning) | 
|  | * */ | 
|  | spin_on(p->procinfo->pcoremap[pcoreid].valid); | 
|  | } else { | 
|  | printk("Core %d was not mapped to proc\n", | 
|  | pcoreid); | 
|  | } | 
|  | diff = stop_timing(begin); | 
|  | } else { | 
|  | /* preempt all cores, warned but no delay */ | 
|  | end_refcnt = kref_refcnt(&p->p_kref) | 
|  | - p->procinfo->num_vcores; | 
|  | begin = start_timing(); | 
|  | proc_preempt_all(p, 1000000); | 
|  | /* a little ghetto, implies no one is using p */ | 
|  | spin_on(kref_refcnt(&p->p_kref) != end_refcnt); | 
|  | diff = stop_timing(begin); | 
|  | } | 
|  | proc_decref(p); | 
|  | } else if (!strcmp(argv[1], "preempt-warn")) { | 
|  | if (argc < 3) { | 
|  | printk("Give me a pid number.\n"); | 
|  | return 1; | 
|  | } | 
|  | struct proc *p = pid2proc(strtol(argv[2], 0, 0)); | 
|  |  | 
|  | if (!p) { | 
|  | printk("No such proc\n"); | 
|  | return 1; | 
|  | } | 
|  | printk("if this hangs, then the process isn't responding.\n"); | 
|  | if (argc == 4) { | 
|  | /* single core being preempted-warned */ | 
|  | uint32_t pcoreid = strtol(argv[3], 0, 0); | 
|  |  | 
|  | spin_lock(&p->proc_lock); | 
|  | uint32_t vcoreid = | 
|  | p->procinfo->pcoremap[pcoreid].vcoreid; | 
|  |  | 
|  | if (!p->procinfo->pcoremap[pcoreid].valid) { | 
|  | printk("Pick a mapped pcore\n"); | 
|  | spin_unlock(&p->proc_lock); | 
|  | return 1; | 
|  | } | 
|  | begin = start_timing(); | 
|  | __proc_preempt_warn(p, vcoreid, 1000000); // 1 sec | 
|  | spin_unlock(&p->proc_lock); | 
|  | /* done when unmapped (right before abandoning) */ | 
|  | spin_on(p->procinfo->pcoremap[pcoreid].valid); | 
|  | diff = stop_timing(begin); | 
|  | } else { | 
|  | /* preempt-warn all cores */ | 
|  | printk("this won't work if they can't yield their last vcore, will stop at 1!\n"); | 
|  | spin_lock(&p->proc_lock); | 
|  | begin = start_timing(); | 
|  | __proc_preempt_warnall(p, 1000000); | 
|  | spin_unlock(&p->proc_lock); | 
|  | /* target cores do the unmapping / changing of the | 
|  | * num_vcores */ | 
|  | spin_on(p->procinfo->num_vcores > 1); | 
|  | diff = stop_timing(begin); | 
|  | } | 
|  | proc_decref(p); | 
|  | } else if (!strcmp(argv[1], "preempt-raw")) { | 
|  | if (argc < 3) { | 
|  | printk("Give me a pid number.\n"); | 
|  | return 1; | 
|  | } | 
|  | struct proc *p = pid2proc(strtol(argv[2], 0, 0)); | 
|  | if (!p) { | 
|  | printk("No such proc\n"); | 
|  | return 1; | 
|  | } | 
|  | if (argc == 4) { | 
|  | /* single core preempted, no warning or waiting */ | 
|  | uint32_t pcoreid = strtol(argv[3], 0, 0); | 
|  |  | 
|  | spin_lock(&p->proc_lock); | 
|  | if (!p->procinfo->pcoremap[pcoreid].valid) { | 
|  | printk("Pick a mapped pcore\n"); | 
|  | spin_unlock(&p->proc_lock); | 
|  | return 1; | 
|  | } | 
|  | begin = start_timing(); | 
|  | __proc_preempt_core(p, pcoreid); | 
|  | if (!p->procinfo->num_vcores) | 
|  | __proc_set_state(p, PROC_RUNNABLE_M); | 
|  | spin_unlock(&p->proc_lock); | 
|  | /* ghetto, since the ksched should be calling all of | 
|  | * this */ | 
|  | __sched_put_idle_core(p, pcoreid); | 
|  | /* done when unmapped (right before abandoning) */ | 
|  | spin_on(p->procinfo->pcoremap[pcoreid].valid); | 
|  | diff = stop_timing(begin); | 
|  | } else { | 
|  | /* preempt all cores, no warning or waiting */ | 
|  | spin_lock(&p->proc_lock); | 
|  | uint32_t pc_arr[p->procinfo->num_vcores]; | 
|  | uint32_t num_revoked; | 
|  |  | 
|  | end_refcnt = kref_refcnt(&p->p_kref) | 
|  | - p->procinfo->num_vcores; | 
|  | begin = start_timing(); | 
|  | num_revoked = __proc_preempt_all(p, pc_arr); | 
|  | __proc_set_state(p, PROC_RUNNABLE_M); | 
|  | spin_unlock(&p->proc_lock); | 
|  | if (num_revoked) | 
|  | __sched_put_idle_cores(p, pc_arr, num_revoked); | 
|  | /* a little ghetto, implies no one else is using p */ | 
|  | spin_on(kref_refcnt(&p->p_kref) != end_refcnt); | 
|  | diff = stop_timing(begin); | 
|  | } | 
|  | proc_decref(p); | 
|  | } else { | 
|  | printk("Bad option\n"); | 
|  | return 1; | 
|  | } | 
|  | printk("[Tired Giraffe Accent] Took %llu usec (%llu nsec) to finish.\n", | 
|  | tsc2usec(diff), tsc2nsec(diff)); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static bool mon_verbose_trace = FALSE; | 
|  | static DEFINE_PERCPU(bool, mon_nmi_trace); | 
|  |  | 
|  | static void emit_hwtf_backtrace(struct hw_trapframe *hw_tf) | 
|  | { | 
|  | if (mon_verbose_trace) { | 
|  | printk("\n"); | 
|  | print_trapframe(hw_tf); | 
|  | backtrace_hwtf(hw_tf); | 
|  | } | 
|  | printk("Core %d is at %p (%s)\n", core_id(), get_hwtf_pc(hw_tf), | 
|  | get_fn_name(get_hwtf_pc(hw_tf))); | 
|  | } | 
|  |  | 
|  | static void emit_vmtf_backtrace(struct vm_trapframe *vm_tf) | 
|  | { | 
|  | if (mon_verbose_trace) { | 
|  | printk("\n"); | 
|  | print_vmtrapframe(vm_tf); | 
|  | } | 
|  | printk("Core %d is at %p\n", core_id(), get_vmtf_pc(vm_tf)); | 
|  | } | 
|  |  | 
|  | /* This is dangerous and could cause a deadlock, since it runs in NMI context. | 
|  | * It's only for monitor debugging, so YMMV.  We pass the type since the kernel | 
|  | * doesn't deal in contexts (yet) */ | 
|  | void emit_monitor_backtrace(int type, void *tf) | 
|  | { | 
|  | if (!PERCPU_VAR(mon_nmi_trace)) | 
|  | return; | 
|  | /* To prevent a spew of output during a lot of perf NMIs, we'll turn off | 
|  | * the monitor output as soon as any NMI hits our core. */ | 
|  | PERCPU_VAR(mon_nmi_trace) = FALSE; | 
|  | print_lock(); | 
|  | if (type == ROS_HW_CTX) | 
|  | emit_hwtf_backtrace((struct hw_trapframe*)tf); | 
|  | else | 
|  | emit_vmtf_backtrace((struct vm_trapframe*)tf); | 
|  | print_kmsgs(core_id()); | 
|  | print_unlock(); | 
|  | } | 
|  |  | 
|  |  | 
|  | int mon_trace(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | int core; | 
|  | if (argc < 2) { | 
|  | printk("Usage: trace OPTION\n"); | 
|  | printk("\tsyscall start [silent (0 or non-zero, NOT the word silent)] [pid]: starts tracing\n"); | 
|  | printk("\tsyscall stop: stops tracing.\n"); | 
|  | printk("\tcoretf COREID: prints PC, -1 for all cores, verbose => TF\n"); | 
|  | printk("\tpcpui [type [coreid]]: runs pcpui trace ring handlers\n"); | 
|  | printk("\tpcpui-reset [noclear]: resets/clears pcpui trace ring\n"); | 
|  | printk("\tverbose: toggles verbosity, depends on trace command\n"); | 
|  | return 1; | 
|  | } | 
|  | if (!strcmp(argv[1], "syscall")) { | 
|  | if (argc < 3) { | 
|  | printk("Need a start or stop.\n"); | 
|  | return 1; | 
|  | } | 
|  | if (!strcmp(argv[2], "start")) { | 
|  | systrace_loud = TRUE; | 
|  | } else if (!strcmp(argv[2], "stop")) { | 
|  | systrace_loud = FALSE; | 
|  | } else { | 
|  | printk("Need a start or stop.\n"); | 
|  | return 1; | 
|  | } | 
|  | } else if (!strcmp(argv[1], "coretf")) { | 
|  | if (argc != 3) { | 
|  | printk("Need a coreid, fool.\n"); | 
|  | return 1; | 
|  | } | 
|  | core = strtol(argv[2], 0, 0); | 
|  | if (core < 0) { | 
|  | printk("Sending NMIs to all cores:\n"); | 
|  | for (int i = 0; i < num_cores; i++) { | 
|  | _PERCPU_VAR(mon_nmi_trace, i) = TRUE; | 
|  | send_nmi(i); | 
|  | udelay(1000000); | 
|  | } | 
|  | } else { | 
|  | printk("Sending NMI core %d:\n", core); | 
|  | if (core >= num_cores) { | 
|  | printk("No such core!  Maybe it's in another cell...\n"); | 
|  | return 1; | 
|  | } | 
|  | _PERCPU_VAR(mon_nmi_trace, core) = TRUE; | 
|  | send_nmi(core); | 
|  | } | 
|  | udelay(1000000); | 
|  | } else if (!strcmp(argv[1], "pcpui")) { | 
|  | int pcpui_type, pcpui_coreid; | 
|  |  | 
|  | if (argc >= 3) | 
|  | pcpui_type = strtol(argv[2], 0, 0); | 
|  | else | 
|  | pcpui_type = 0; | 
|  | printk("\nRunning PCPUI Trace Ring handlers for type %d\n", | 
|  | pcpui_type); | 
|  | if (argc >= 4) { | 
|  | pcpui_coreid = strtol(argv[3], 0, 0); | 
|  | pcpui_tr_foreach(pcpui_coreid, pcpui_type); | 
|  | } else { | 
|  | pcpui_tr_foreach_all(pcpui_type); | 
|  | } | 
|  | } else if (!strcmp(argv[1], "pcpui-reset")) { | 
|  | if (argc >= 3) { | 
|  | printk("\nResetting all PCPUI Trace Rings\n"); | 
|  | pcpui_tr_reset_all(); | 
|  | } else { | 
|  | printk("\nResetting/clearing all PCPUI Trace Rings\n"); | 
|  | pcpui_tr_reset_and_clear_all(); | 
|  | } | 
|  | } else if (!strcmp(argv[1], "verbose")) { | 
|  | if (mon_verbose_trace) { | 
|  | printk("Turning trace verbosity off\n"); | 
|  | mon_verbose_trace = FALSE; | 
|  | } else { | 
|  | printk("Turning trace verbosity on\n"); | 
|  | mon_verbose_trace = TRUE; | 
|  | } | 
|  | } else if (!strcmp(argv[1], "opt2")) { | 
|  | if (argc != 3) { | 
|  | printk("ERRRRRRRRRR.\n"); | 
|  | return 1; | 
|  | } | 
|  | print_proc_info(strtol(argv[2], 0, 0), 0); | 
|  | } else { | 
|  | printk("Bad option\n"); | 
|  | return 1; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int mon_monitor(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | if (argc < 2) { | 
|  | printk("Usage: monitor COREID\n"); | 
|  | return 1; | 
|  | } | 
|  | uint32_t core = strtol(argv[1], 0, 0); | 
|  | if (core >= num_cores) { | 
|  | printk("No such core!  Maybe it's in another cell...\n"); | 
|  | return 1; | 
|  | } | 
|  | send_kernel_message(core, __run_mon, 0, 0, 0, KMSG_ROUTINE); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /***** Kernel monitor command interpreter *****/ | 
|  |  | 
|  | #define WHITESPACE "\t\r\n " | 
|  | #define MAXARGS 16 | 
|  |  | 
|  |  | 
|  | int onecmd(int argc, char *argv[], struct hw_trapframe *hw_tf) { | 
|  | int i; | 
|  | if (!argc) | 
|  | return -1; | 
|  | for (i = 0; i < NCOMMANDS; i++) { | 
|  | if (strcmp(argv[0], commands[i].name) == 0) | 
|  | return commands[i].func(argc, argv, hw_tf); | 
|  | } | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | void __run_mon(uint32_t srcid, long a0, long a1, long a2) | 
|  | { | 
|  | monitor(0); | 
|  | } | 
|  |  | 
|  | static int runcmd(char *real_buf, struct hw_trapframe *hw_tf) { | 
|  | char * buf = real_buf; | 
|  | int argc; | 
|  | char *argv[MAXARGS]; | 
|  | int i; | 
|  |  | 
|  | // Parse the command buffer into whitespace-separated arguments | 
|  | argc = 0; | 
|  | argv[argc] = 0; | 
|  | /* Discard initial 'm ', which is a common mistake when using 'm' a lot | 
|  | */ | 
|  | if ((buf[0] == 'm') && (buf[1] == ' ')) | 
|  | buf += 2; | 
|  | while (1) { | 
|  | // gobble whitespace | 
|  | while (*buf && strchr(WHITESPACE, *buf)) | 
|  | *buf++ = 0; | 
|  | if (*buf == 0) | 
|  | break; | 
|  |  | 
|  | // save and scan past next arg | 
|  | if (argc == MAXARGS-1) { | 
|  | cprintf("Too many arguments (max %d)\n", MAXARGS); | 
|  | return 0; | 
|  | } | 
|  | //This will get fucked at runtime..... in the ASS | 
|  | argv[argc++] = buf; | 
|  | while (*buf && !strchr(WHITESPACE, *buf)) | 
|  | buf++; | 
|  | } | 
|  | argv[argc] = 0; | 
|  |  | 
|  | // Lookup and invoke the command | 
|  | if (argc == 0) | 
|  | return 0; | 
|  | for (i = 0; i < NCOMMANDS; i++) { | 
|  | if (strcmp(argv[0], commands[i].name) == 0) | 
|  | return commands[i].func(argc, argv, hw_tf); | 
|  | } | 
|  | cprintf("Unknown command '%s'\n", argv[0]); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | void monitor(struct hw_trapframe *hw_tf) | 
|  | { | 
|  | #define MON_CMD_LENGTH 256 | 
|  | char buf[MON_CMD_LENGTH]; | 
|  | int cnt; | 
|  | int coreid = core_id_early(); | 
|  |  | 
|  | /* they are always disabled, since we have this irqsave lock */ | 
|  | if (irq_is_enabled()) | 
|  | printk("Entering Nanwan's Dungeon on Core %d (Ints on):\n", | 
|  | coreid); | 
|  | else | 
|  | printk("Entering Nanwan's Dungeon on Core %d (Ints off):\n", | 
|  | coreid); | 
|  | printk("Type 'help' for a list of commands.\n"); | 
|  |  | 
|  | if (hw_tf != NULL) | 
|  | print_trapframe(hw_tf); | 
|  |  | 
|  | while (1) { | 
|  | /* on occasion, the kernel monitor can migrate (like if you run | 
|  | * something that blocks / syncs and wakes up on another core) | 
|  | */ | 
|  | cmb(); | 
|  | cnt = readline(buf, MON_CMD_LENGTH, "ROS(Core %d)> ", | 
|  | core_id_early()); | 
|  | if (cnt > 0) { | 
|  | buf[cnt] = 0; | 
|  | if (runcmd(buf, hw_tf) < 0) | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | int mon_shell(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | char *l_argv[2] = {"/bin/bash", "bash"}; | 
|  | return mon_bin_run(2, l_argv, hw_tf); | 
|  | } | 
|  |  | 
|  | int mon_alarm(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | if (argc < 2) { | 
|  | printk("Usage: alarm OPTION\n"); | 
|  | printk("\tpcpu: print full alarm tchains from every core\n"); | 
|  | return 1; | 
|  | } | 
|  | if (!strcmp(argv[1], "pcpu")) { | 
|  | print_pcpu_chains(); | 
|  | } else { | 
|  | printk("Bad option\n"); | 
|  | return 1; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void show_msr(struct hw_trapframe *unused, void *v) | 
|  | { | 
|  | int core = core_id(); | 
|  | uint64_t val; | 
|  | uint32_t msr = *(uint32_t *)v; | 
|  |  | 
|  | val = read_msr(msr); | 
|  | printk("%d: %08x: %016llx\n", core, msr, val); | 
|  | } | 
|  |  | 
|  | struct set { | 
|  | uint32_t msr; | 
|  | uint64_t val; | 
|  | }; | 
|  |  | 
|  | static void set_msr(struct hw_trapframe *unused, void *v) | 
|  | { | 
|  | int core = core_id(); | 
|  | struct set *s = v; | 
|  | uint32_t msr = s->msr; | 
|  | uint64_t val = s->val; | 
|  |  | 
|  | write_msr(msr, val); | 
|  | val = read_msr(msr); | 
|  | printk("%d: %08x: %016llx\n", core, msr, val); | 
|  | } | 
|  |  | 
|  | int mon_msr(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | #ifndef CONFIG_X86 | 
|  | cprintf("Not on this architecture\n"); | 
|  | return 1; | 
|  | #else | 
|  | uint64_t val; | 
|  | uint32_t msr; | 
|  |  | 
|  | if (argc < 2 || argc > 3) { | 
|  | printk("Usage: msr register [value]\n"); | 
|  | return 1; | 
|  | } | 
|  | msr = strtoul(argv[1], 0, 16); | 
|  | handler_wrapper_t *w; | 
|  | smp_call_function_all(show_msr, &msr, &w); | 
|  | smp_call_wait(w); | 
|  |  | 
|  | if (argc < 3) | 
|  | return 0; | 
|  | /* somewhat bogus on 32 bit. */ | 
|  | val = strtoul(argv[2], 0, 16); | 
|  |  | 
|  | struct set set; | 
|  | set.msr = msr; | 
|  | set.val = val; | 
|  | smp_call_function_all(set_msr, &set, &w); | 
|  | smp_call_wait(w); | 
|  | return 0; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | int mon_db(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | pid_t pid = -1; | 
|  |  | 
|  | if (argc < 2) { | 
|  | printk("Usage: db OPTION\n"); | 
|  | printk("\tblk [PID]: print all blocked kthreads\n"); | 
|  | printk("\taddr PID 0xADDR: lookup ADDR's file/vmr info\n"); | 
|  | printk("\trv WAITER: backtrace rendez alarm waiter\n"); | 
|  | return 1; | 
|  | } | 
|  | if (!strcmp(argv[1], "blk") || !strcmp(argv[1], "sem")) { | 
|  | if (argc > 2) | 
|  | pid = strtol(argv[2], 0, 0); | 
|  | print_db_blk_info(pid); | 
|  | } else if (!strcmp(argv[1], "addr")) { | 
|  | if (argc < 4) { | 
|  | printk("Usage: db addr PID 0xADDR\n"); | 
|  | return 1; | 
|  | } | 
|  | debug_addr_pid(strtol(argv[2], 0, 10), strtol(argv[3], 0, 16)); | 
|  | } else if (!strcmp(argv[1], "rv")) { | 
|  | if (argc < 3) { | 
|  | printk("Usage: db rv 0xWAITER\n"); | 
|  | return 1; | 
|  | } | 
|  | rendez_debug_waiter((struct alarm_waiter*)strtoul(argv[2], 0, | 
|  | 16)); | 
|  | } else { | 
|  | printk("Bad option\n"); | 
|  | return 1; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int mon_px(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | pid_t pid = 0; | 
|  | struct proc *p; | 
|  |  | 
|  | if (argc == 2) | 
|  | pid = strtol(argv[1], 0, 0); | 
|  | if (!pid) { | 
|  | set_printx(2); | 
|  | printk("Printxing is now %sabled\n", printx_on ? "en" : "dis"); | 
|  | return 0; | 
|  | } | 
|  | p = pid2proc(pid); | 
|  | if (!p) { | 
|  | printk("No proc with pid %d\n", pid); | 
|  | return 1; | 
|  | } | 
|  | p->procdata->printx_on = !p->procdata->printx_on; | 
|  | proc_decref(p); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Super hack.  Given a kernel hw_tf, we hack the RIP to smp_idle, then return | 
|  | * to it.  Any locks or other stuff being done is completely lost, so you could | 
|  | * deadlock.  This gets out of the "we're totall screwed, but don't want to | 
|  | * reboot right now", typically caused by screw-ups from the monitor. */ | 
|  | int mon_kpfret(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | struct per_cpu_info *pcpui = &per_cpu_info[core_id()]; | 
|  |  | 
|  | /* if monitor had a TF, try to use that */ | 
|  | if (!hw_tf) { | 
|  | if (argc < 2) { | 
|  | printk("Usage: kpfret HW_TF\n"); | 
|  | return 1; | 
|  | } | 
|  | /* the hw_tf passed in is the one we got from monitor, which is | 
|  | * 0 from panics. */ | 
|  | hw_tf = (struct hw_trapframe*)strtol(argv[1], 0, 16); | 
|  | } | 
|  |  | 
|  | if (!in_kernel(hw_tf)) { | 
|  | printk("hw_tf %p was not a kernel tf!\n", hw_tf); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | #ifdef CONFIG_X86 | 
|  | hw_tf->tf_rip = (uintptr_t)smp_idle; | 
|  | dec_ktrap_depth(pcpui); | 
|  |  | 
|  | asm volatile("mov %0, %%rsp;" | 
|  | "addq $0x10, %%rsp;" | 
|  | "popq %%rax;" | 
|  | "popq %%rbx;" | 
|  | "popq %%rcx;" | 
|  | "popq %%rdx;" | 
|  | "popq %%rbp;" | 
|  | "popq %%rsi;" | 
|  | "popq %%rdi;" | 
|  | "popq %%r8;" | 
|  | "popq %%r9;" | 
|  | "popq %%r10;" | 
|  | "popq %%r11;" | 
|  | "popq %%r12;" | 
|  | "popq %%r13;" | 
|  | "popq %%r14;" | 
|  | "popq %%r15;" | 
|  | "addq $0x10, %%rsp;" | 
|  | "iretq;" | 
|  | : : "r"(hw_tf)); | 
|  | assert(0); | 
|  | #else | 
|  | printk("KPF return not supported\n"); | 
|  | return -1; | 
|  | #endif /* CONFIG_X86 */ | 
|  | } | 
|  |  | 
|  | int mon_ks(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | if (argc < 2) { | 
|  | usage: | 
|  | printk("Usage: ks OPTION\n"); | 
|  | printk("\tidles: show idle core map\n"); | 
|  | printk("\tdiag: scheduler diagnostic report\n"); | 
|  | printk("\tresources: show resources wanted/granted for all procs\n"); | 
|  | printk("\tsort: sorts the idlecoremap, 1..n\n"); | 
|  | printk("\tnc PCOREID: sets the next CG core allocated\n"); | 
|  | return 1; | 
|  | } | 
|  | if (!strcmp(argv[1], "idles")) { | 
|  | print_idle_core_map(); | 
|  | } else if (!strcmp(argv[1], "diag")) { | 
|  | sched_diag(); | 
|  | } else if (!strcmp(argv[1], "resources")) { | 
|  | print_all_resources(); | 
|  | } else if (!strcmp(argv[1], "sort")) { | 
|  | sort_idle_cores(); | 
|  | } else if (!strcmp(argv[1], "nc")) { | 
|  | if (argc != 3) { | 
|  | printk("Need a pcore number.\n"); | 
|  | return 1; | 
|  | } | 
|  | next_core_to_alloc(strtol(argv[2], 0, 0)); | 
|  | } else { | 
|  | printk("Bad option %s\n", argv[1]); | 
|  | goto usage; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Prints info about a core.  Optional first arg == coreid. */ | 
|  | int mon_coreinfo(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | struct per_cpu_info *pcpui; | 
|  | struct kthread *kth; | 
|  | int coreid = core_id(); | 
|  |  | 
|  | if (argc >= 2) | 
|  | coreid = strtol(argv[1], 0, 0); | 
|  | pcpui = &per_cpu_info[coreid]; | 
|  | printk("Core %d:\n\tcur_proc %d\n\towning proc %d, owning vc %d\n", | 
|  | coreid, pcpui->cur_proc ? pcpui->cur_proc->pid : 0, | 
|  | pcpui->owning_proc ? pcpui->owning_proc->pid : 0, | 
|  | pcpui->owning_vcoreid != 0xdeadbeef ? pcpui->owning_vcoreid : 0); | 
|  | kth = pcpui->cur_kthread; | 
|  | if (kth) { | 
|  | /* kth->proc is only used when the kthread is sleeping.  when | 
|  | * it's running, we care about cur_proc.  if we're here, proc | 
|  | * should be 0 unless the kth is concurrently sleeping (we | 
|  | * called this remotely) */ | 
|  | printk("\tkthread %p (%s), sysc %p (%d)\n", kth, kth->name, | 
|  | kth->sysc, kth->sysc ? kth->sysc->num : -1); | 
|  | } else { | 
|  | /* Can happen during early boot */ | 
|  | printk("\tNo kthread!\n"); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int mon_hexdump(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | struct proc *p = NULL; | 
|  | uintptr_t switch_state; | 
|  | pid_t pid; | 
|  | uintptr_t start; | 
|  | size_t len; | 
|  |  | 
|  | assert(argc >= 1); | 
|  | if (argc < 4) { | 
|  | printk("Usage: %s PID ADDR LEN\n", argv[0]); | 
|  | printk("    PID == 0 for kernel / don't care\n"); | 
|  | return 1; | 
|  | } | 
|  | pid = strtol(argv[1], 0, 0); | 
|  | start = strtoul(argv[2], 0, 0); | 
|  | len = strtoul(argv[3], 0, 0); | 
|  | if (pid) { | 
|  | p = pid2proc(pid); | 
|  | if (!p) { | 
|  | printk("No proc with pid %d\n", pid); | 
|  | return 1; | 
|  | } | 
|  | switch_state = switch_to(p); | 
|  | } | 
|  | hexdump((void*)start, len); | 
|  | if (p) { | 
|  | switch_back(p, switch_state); | 
|  | proc_decref(p); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int mon_pahexdump(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | uintptr_t start; | 
|  | size_t len; | 
|  |  | 
|  | assert(argc >= 1); | 
|  | if (argc < 3) { | 
|  | printk("Usage: %s PHYS_ADDR LEN\n", argv[0]); | 
|  | return 1; | 
|  | } | 
|  | start = strtoul(argv[1], 0, 0); | 
|  | len = strtoul(argv[2], 0, 0); | 
|  | pahexdump(start, len); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int mon_dmesg(int argc, char **argv, struct hw_trapframe *hw_tf) | 
|  | { | 
|  | kprof_dump_data(); | 
|  | return 0; | 
|  | } |