/* * Copyright (C) 2005 Jakub Jermar * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * This file is meant to contain all wrapper functions for * all kconsole commands. The point is in separating * kconsole specific wrappers from kconsole-unaware functions * from other subsystems. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include
#include #include #include #include /** Data and methods for 'help' command. */ static int cmd_help(cmd_arg_t *argv); static cmd_info_t help_info = { .name = "help", .description = "List of supported commands.", .func = cmd_help, .argc = 0 }; static cmd_info_t exit_info = { .name = "exit", .description ="Exit kconsole", .argc = 0 }; /** Data and methods for 'description' command. */ static int cmd_desc(cmd_arg_t *argv); static void desc_help(void); static char desc_buf[MAX_CMDLINE+1]; static cmd_arg_t desc_argv = { .type = ARG_TYPE_STRING, .buffer = desc_buf, .len = sizeof(desc_buf) }; static cmd_info_t desc_info = { .name = "describe", .description = "Describe specified command.", .help = desc_help, .func = cmd_desc, .argc = 1, .argv = &desc_argv }; /** Data and methods for 'symaddr' command. */ static int cmd_symaddr(cmd_arg_t *argv); static char symaddr_buf[MAX_CMDLINE+1]; static cmd_arg_t symaddr_argv = { .type = ARG_TYPE_STRING, .buffer = symaddr_buf, .len = sizeof(symaddr_buf) }; static cmd_info_t symaddr_info = { .name = "symaddr", .description = "Return symbol address.", .func = cmd_symaddr, .argc = 1, .argv = &symaddr_argv }; static char set_buf[MAX_CMDLINE+1]; static int cmd_set4(cmd_arg_t *argv); static cmd_arg_t set4_argv[] = { { .type = ARG_TYPE_STRING, .buffer = set_buf, .len = sizeof(set_buf) }, { .type = ARG_TYPE_INT } }; static cmd_info_t set4_info = { .name = "set4", .description = "set - 4byte version", .func = cmd_set4, .argc = 2, .argv = set4_argv }; /** Data and methods for 'call0' command. */ static char call0_buf[MAX_CMDLINE+1]; static char carg1_buf[MAX_CMDLINE+1]; static char carg2_buf[MAX_CMDLINE+1]; static char carg3_buf[MAX_CMDLINE+1]; static int cmd_call0(cmd_arg_t *argv); static cmd_arg_t call0_argv = { .type = ARG_TYPE_STRING, .buffer = call0_buf, .len = sizeof(call0_buf) }; static cmd_info_t call0_info = { .name = "call0", .description = "call0 -> call function().", .func = cmd_call0, .argc = 1, .argv = &call0_argv }; /** Data and methods for 'call1' command. */ static int cmd_call1(cmd_arg_t *argv); static cmd_arg_t call1_argv[] = { { .type = ARG_TYPE_STRING, .buffer = call0_buf, .len = sizeof(call0_buf) }, { .type = ARG_TYPE_VAR, .buffer = carg1_buf, .len = sizeof(carg1_buf) } }; static cmd_info_t call1_info = { .name = "call1", .description = "call1 -> call function(arg1).", .func = cmd_call1, .argc = 2, .argv = call1_argv }; /** Data and methods for 'call2' command. */ static int cmd_call2(cmd_arg_t *argv); static cmd_arg_t call2_argv[] = { { .type = ARG_TYPE_STRING, .buffer = call0_buf, .len = sizeof(call0_buf) }, { .type = ARG_TYPE_VAR, .buffer = carg1_buf, .len = sizeof(carg1_buf) }, { .type = ARG_TYPE_VAR, .buffer = carg2_buf, .len = sizeof(carg2_buf) } }; static cmd_info_t call2_info = { .name = "call2", .description = "call2 -> call function(arg1,arg2).", .func = cmd_call2, .argc = 3, .argv = call2_argv }; /** Data and methods for 'call3' command. */ static int cmd_call3(cmd_arg_t *argv); static cmd_arg_t call3_argv[] = { { .type = ARG_TYPE_STRING, .buffer = call0_buf, .len = sizeof(call0_buf) }, { .type = ARG_TYPE_VAR, .buffer = carg1_buf, .len = sizeof(carg1_buf) }, { .type = ARG_TYPE_VAR, .buffer = carg2_buf, .len = sizeof(carg2_buf) }, { .type = ARG_TYPE_VAR, .buffer = carg3_buf, .len = sizeof(carg3_buf) } }; static cmd_info_t call3_info = { .name = "call3", .description = "call3 -> call function(arg1,arg2,arg3).", .func = cmd_call3, .argc = 4, .argv = call3_argv }; /** Data and methods for 'halt' command. */ static int cmd_halt(cmd_arg_t *argv); static cmd_info_t halt_info = { .name = "halt", .description = "Halt the kernel.", .func = cmd_halt, .argc = 0 }; /** Data and methods for 'tlb' command. */ static int cmd_tlb(cmd_arg_t *argv); cmd_info_t tlb_info = { .name = "tlb", .description = "Print TLB of current processor.", .help = NULL, .func = cmd_tlb, .argc = 0, .argv = NULL }; static int cmd_threads(cmd_arg_t *argv); static cmd_info_t threads_info = { .name = "threads", .description = "List all threads", .func = cmd_threads, .argc = 0 }; static int cmd_tasks(cmd_arg_t *argv); static cmd_info_t tasks_info = { .name = "tasks", .description = "List all tasks", .func = cmd_tasks, .argc = 0 }; static int cmd_sched(cmd_arg_t *argv); static cmd_info_t sched_info = { .name = "scheduler", .description = "List all scheduler information", .func = cmd_sched, .argc = 0 }; static int cmd_slabs(cmd_arg_t *argv); static cmd_info_t slabs_info = { .name = "slabs", .description = "List SLAB caches.", .func = cmd_slabs, .argc = 0 }; /** Data and methods for 'zones' command */ static int cmd_zones(cmd_arg_t *argv); static cmd_info_t zones_info = { .name = "zones", .description = "List of memory zones.", .func = cmd_zones, .argc = 0 }; /** Data and methods for 'zone' command */ static int cmd_zone(cmd_arg_t *argv); static cmd_arg_t zone_argv = { .type = ARG_TYPE_INT, }; static cmd_info_t zone_info = { .name = "zone", .description = "Show memory zone structure.", .func = cmd_zone, .argc = 1, .argv = &zone_argv }; /** Data and methods for 'cpus' command. */ static int cmd_cpus(cmd_arg_t *argv); cmd_info_t cpus_info = { .name = "cpus", .description = "List all processors.", .help = NULL, .func = cmd_cpus, .argc = 0, .argv = NULL }; /** Data and methods for 'version' command. */ static int cmd_version(cmd_arg_t *argv); cmd_info_t version_info = { .name = "version", .description = "Print version information.", .help = NULL, .func = cmd_version, .argc = 0, .argv = NULL }; static cmd_info_t *basic_commands[] = { &call0_info, &call1_info, &call2_info, &call3_info, &cpus_info, &desc_info, &exit_info, &halt_info, &help_info, &set4_info, &slabs_info, &symaddr_info, &sched_info, &threads_info, &tasks_info, &tlb_info, &version_info, &zones_info, &zone_info, NULL }; /** Initialize command info structure. * * @param cmd Command info structure. * */ void cmd_initialize(cmd_info_t *cmd) { spinlock_initialize(&cmd->lock, "cmd"); link_initialize(&cmd->link); } /** Initialize and register commands. */ void cmd_init(void) { int i; for (i=0;basic_commands[i]; i++) { cmd_initialize(basic_commands[i]); if (!cmd_register(basic_commands[i])) panic("could not register command %s\n", basic_commands[i]->name); } } /** List supported commands. * * @param argv Argument vector. * * @return 0 on failure, 1 on success. */ int cmd_help(cmd_arg_t *argv) { link_t *cur; spinlock_lock(&cmd_lock); for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) { cmd_info_t *hlp; hlp = list_get_instance(cur, cmd_info_t, link); spinlock_lock(&hlp->lock); printf("%s - %s\n", hlp->name, hlp->description); spinlock_unlock(&hlp->lock); } spinlock_unlock(&cmd_lock); return 1; } /** Describe specified command. * * @param argv Argument vector. * * @return 0 on failure, 1 on success. */ int cmd_desc(cmd_arg_t *argv) { link_t *cur; spinlock_lock(&cmd_lock); for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) { cmd_info_t *hlp; hlp = list_get_instance(cur, cmd_info_t, link); spinlock_lock(&hlp->lock); if (strncmp(hlp->name, (const char *) argv->buffer, strlen(hlp->name)) == 0) { printf("%s - %s\n", hlp->name, hlp->description); if (hlp->help) hlp->help(); spinlock_unlock(&hlp->lock); break; } spinlock_unlock(&hlp->lock); } spinlock_unlock(&cmd_lock); return 1; } /** Search symbol table */ int cmd_symaddr(cmd_arg_t *argv) { symtab_print_search(argv->buffer); return 1; } /** Call function with zero parameters */ int cmd_call0(cmd_arg_t *argv) { __address symaddr; char *symbol; __native (*f)(void); symaddr = get_symbol_addr(argv->buffer); if (!symaddr) printf("Symbol %s not found.\n", argv->buffer); else if (symaddr == (__address) -1) { symtab_print_search(argv->buffer); printf("Duplicate symbol, be more specific.\n"); } else { symbol = get_symtab_entry(symaddr); printf("Calling f(): 0x%p: %s\n", symaddr, symbol); f = (__native (*)(void)) symaddr; printf("Result: 0x%p\n", f()); } return 1; } /** Call function with one parameter */ int cmd_call1(cmd_arg_t *argv) { __address symaddr; char *symbol; __native (*f)(__native,...); __native arg1 = argv[1].intval; symaddr = get_symbol_addr(argv->buffer); if (!symaddr) printf("Symbol %s not found.\n", argv->buffer); else if (symaddr == (__address) -1) { symtab_print_search(argv->buffer); printf("Duplicate symbol, be more specific.\n"); } else { symbol = get_symtab_entry(symaddr); printf("Calling f(0x%x): 0x%p: %s\n", arg1, symaddr, symbol); f = (__native (*)(__native,...)) symaddr; printf("Result: 0x%p\n", f(arg1)); } return 1; } /** Call function with two parameters */ int cmd_call2(cmd_arg_t *argv) { __address symaddr; char *symbol; __native (*f)(__native,__native,...); __native arg1 = argv[1].intval; __native arg2 = argv[2].intval; symaddr = get_symbol_addr(argv->buffer); if (!symaddr) printf("Symbol %s not found.\n", argv->buffer); else if (symaddr == (__address) -1) { symtab_print_search(argv->buffer); printf("Duplicate symbol, be more specific.\n"); } else { symbol = get_symtab_entry(symaddr); printf("Calling f(0x%x,0x%x): 0x%p: %s\n", arg1, arg2, symaddr, symbol); f = (__native (*)(__native,__native,...)) symaddr; printf("Result: 0x%p\n", f(arg1, arg2)); } return 1; } /** Call function with three parameters */ int cmd_call3(cmd_arg_t *argv) { __address symaddr; char *symbol; __native (*f)(__native,__native,__native,...); __native arg1 = argv[1].intval; __native arg2 = argv[2].intval; __native arg3 = argv[3].intval; symaddr = get_symbol_addr(argv->buffer); if (!symaddr) printf("Symbol %s not found.\n", argv->buffer); else if (symaddr == (__address) -1) { symtab_print_search(argv->buffer); printf("Duplicate symbol, be more specific.\n"); } else { symbol = get_symtab_entry(symaddr); printf("Calling f(0x%x,0x%x, 0x%x): 0x%p: %s\n", arg1, arg2, arg3, symaddr, symbol); f = (__native (*)(__native,__native,__native,...)) symaddr; printf("Result: 0x%p\n", f(arg1, arg2, arg3)); } return 1; } /** Print detailed description of 'describe' command. */ void desc_help(void) { printf("Syntax: describe command_name\n"); } /** Halt the kernel. * * @param argv Argument vector (ignored). * * @return 0 on failure, 1 on success (never returns). */ int cmd_halt(cmd_arg_t *argv) { halt(); return 1; } /** Command for printing TLB contents. * * @param argv Not used. * * @return Always returns 1. */ int cmd_tlb(cmd_arg_t *argv) { tlb_print(); return 1; } /** Write 4 byte value to address */ int cmd_set4(cmd_arg_t *argv) { __u32 *addr ; __u32 arg1 = argv[1].intval; bool pointer = false; if (((char *)argv->buffer)[0] == '*') { addr = (__u32 *) get_symbol_addr(argv->buffer+1); pointer = true; } else if (((char *)argv->buffer)[0] >= '0' && ((char *)argv->buffer)[0] <= '9') addr = (__u32 *)atoi((char *)argv->buffer); else addr = (__u32 *)get_symbol_addr(argv->buffer); if (!addr) printf("Symbol %s not found.\n", argv->buffer); else if (addr == (__u32 *) -1) { symtab_print_search(argv->buffer); printf("Duplicate symbol, be more specific.\n"); } else { if (pointer) addr = (__u32 *)(*(__native *)addr); printf("Writing 0x%x -> 0x%p\n", arg1, addr); *addr = arg1; } return 1; } /** Command for listings SLAB caches * * @param argv Ignores * * @return Always 1 */ int cmd_slabs(cmd_arg_t * argv) { slab_print_list(); return 1; } /** Command for listings Thread information * * @param argv Ignores * * @return Always 1 */ int cmd_threads(cmd_arg_t * argv) { thread_print_list(); return 1; } /** Command for listings Task information * * @param argv Ignores * * @return Always 1 */ int cmd_tasks(cmd_arg_t * argv) { task_print_list(); return 1; } /** Command for listings Thread information * * @param argv Ignores * * @return Always 1 */ int cmd_sched(cmd_arg_t * argv) { sched_print_list(); return 1; } /** Command for listing memory zones * * @param argv Ignored * * return Always 1 */ int cmd_zones(cmd_arg_t * argv) { zone_print_list(); return 1; } /** Command for memory zone details * * @param argv Integer argument from cmdline expected * * return Always 1 */ int cmd_zone(cmd_arg_t * argv) { zone_print_one(argv[0].intval); return 1; } /** Command for listing processors. * * @param argv Ignored. * * return Always 1. */ int cmd_cpus(cmd_arg_t *argv) { cpu_list(); return 1; } /** Command for printing kernel version. * * @param argv Ignored. * * return Always 1. */ int cmd_version(cmd_arg_t *argv) { version_print(); return 1; }