| // 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); | 
 | 		if (!proc_vcoreid_is_safe(p, vcoreid)) { | 
 | 			printk("Bad vcoreid %d\n", vcoreid); | 
 | 			proc_decref(p); | 
 | 			return -1; | 
 | 		} | 
 | 		/* 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; | 
 | } |