HelenOS sources
This source file includes following definitions.
- cmd_initialize
- cmd_init
- cmd_help
- cmd_pio_read_8
- cmd_pio_read_16
- cmd_pio_read_32
- cmd_pio_write_8
- cmd_pio_write_16
- cmd_pio_write_32
- cmd_reboot
- cmd_uptime
- cmd_desc
- cmd_symaddr
- cmd_call0
- cmd_mcall0
- cmd_call1
- cmd_call2
- cmd_call3
- desc_help
- cmd_halt
- cmd_tlb
- cmd_physmem
- cmd_set4
- cmd_caches
- cmd_sysinfo
- cmd_threads
- cmd_tasks
- cmd_btrace
- cmd_sched
- cmd_zones
- cmd_zone
- cmd_ipc
- cmd_kill
- cmd_cpus
- cmd_version
- cmd_continue
- run_test
- run_bench
- list_tests
- cmd_test
- cmd_bench
- cmd_printbench
#include <assert.h>
#include <console/cmd.h>
#include <console/console.h>
#include <console/kconsole.h>
#include <stdio.h>
#include <log.h>
#include <panic.h>
#include <typedefs.h>
#include <adt/list.h>
#include <arch.h>
#include <config.h>
#include <halt.h>
#include <str.h>
#include <macros.h>
#include <cpu.h>
#include <mm/tlb.h>
#include <mm/km.h>
#include <arch/mm/tlb.h>
#include <mm/frame.h>
#include <main/version.h>
#include <mm/slab.h>
#include <proc/scheduler.h>
#include <proc/thread.h>
#include <proc/task.h>
#include <ipc/ipc.h>
#include <ipc/irq.h>
#include <ipc/event.h>
#include <sysinfo/sysinfo.h>
#include <symtab.h>
#include <errno.h>
#include <stdlib.h>
#ifdef CONFIG_TEST
#include <test.h>
#endif
static int cmd_help(cmd_arg_t *argv);
static cmd_info_t help_info = {
.name = "help",
.description = "List supported commands.",
.func = cmd_help,
.argc = 0
};
static int cmd_pio_read_8(cmd_arg_t *argv);
static cmd_arg_t pio_read_8_argv[] = { { .type = ARG_TYPE_INT } };
static cmd_info_t pio_read_8_info = {
.name = "pio_read_8",
.description = "pio_read_8 <address> Read 1 byte from memory (or port).",
.func = cmd_pio_read_8,
.argc = 1,
.argv = pio_read_8_argv
};
static int cmd_pio_read_16(cmd_arg_t *argv);
static cmd_arg_t pio_read_16_argv[] = { { .type = ARG_TYPE_INT } };
static cmd_info_t pio_read_16_info = {
.name = "pio_read_16",
.description = "pio_read_16 <address> Read 2 bytes from memory (or port).",
.func = cmd_pio_read_16,
.argc = 1,
.argv = pio_read_16_argv
};
static int cmd_pio_read_32(cmd_arg_t *argv);
static cmd_arg_t pio_read_32_argv[] = { { .type = ARG_TYPE_INT } };
static cmd_info_t pio_read_32_info = {
.name = "pio_read_32",
.description = "pio_read_32 <address> Read 4 bytes from memory (or port).",
.func = cmd_pio_read_32,
.argc = 1,
.argv = pio_read_32_argv
};
static int cmd_pio_write_8(cmd_arg_t *argv);
static cmd_arg_t pio_write_8_argv[] = {
{ .type = ARG_TYPE_INT },
{ .type = ARG_TYPE_INT }
};
static cmd_info_t pio_write_8_info = {
.name = "pio_write_8",
.description = "pio_write_8 <address> <value> Write 1 byte to memory (or port).",
.func = cmd_pio_write_8,
.argc = 2,
.argv = pio_write_8_argv
};
static int cmd_pio_write_16(cmd_arg_t *argv);
static cmd_arg_t pio_write_16_argv[] = {
{ .type = ARG_TYPE_INT },
{ .type = ARG_TYPE_INT }
};
static cmd_info_t pio_write_16_info = {
.name = "pio_write_16",
.description = "pio_write_16 <address> <value> Write 2 bytes to memory (or port).",
.func = cmd_pio_write_16,
.argc = 2,
.argv = pio_write_16_argv
};
static int cmd_pio_write_32(cmd_arg_t *argv);
static cmd_arg_t pio_write_32_argv[] = {
{ .type = ARG_TYPE_INT },
{ .type = ARG_TYPE_INT }
};
static cmd_info_t pio_write_32_info = {
.name = "pio_write_32",
.description = "pio_write_32 <address> <value> Write 4 bytes to memory (or port).",
.func = cmd_pio_write_32,
.argc = 2,
.argv = pio_write_32_argv
};
static int cmd_reboot(cmd_arg_t *argv);
static cmd_info_t reboot_info = {
.name = "reboot",
.description = "Reboot system.",
.func = cmd_reboot,
.argc = 0
};
static int cmd_uptime(cmd_arg_t *argv);
static cmd_info_t uptime_info = {
.name = "uptime",
.description = "Show system uptime.",
.func = cmd_uptime,
.argc = 0
};
static int cmd_continue(cmd_arg_t *argv);
static cmd_info_t continue_info = {
.name = "continue",
.description = "Return console back to userspace.",
.func = cmd_continue,
.argc = 0
};
#ifdef CONFIG_TEST
static char test_buf[MAX_CMDLINE + 1];
static int cmd_test(cmd_arg_t *argv);
static cmd_arg_t test_argv[] = {
{
.type = ARG_TYPE_STRING_OPTIONAL,
.buffer = test_buf,
.len = sizeof(test_buf)
}
};
static cmd_info_t test_info = {
.name = "test",
.description = "<test> List kernel tests or run a test.",
.func = cmd_test,
.argc = 1,
.argv = test_argv,
.hints_enum = tests_hints_enum
};
static int cmd_bench(cmd_arg_t *argv);
static cmd_arg_t bench_argv[] = {
{
.type = ARG_TYPE_STRING,
.buffer = test_buf,
.len = sizeof(test_buf)
},
{
.type = ARG_TYPE_INT,
}
};
static cmd_info_t bench_info = {
.name = "bench",
.description = "<test> <count> Run kernel test as benchmark.",
.func = cmd_bench,
.argc = 2,
.argv = bench_argv
};
static int cmd_printbench(cmd_arg_t *argv);
static cmd_info_t printbench_info = {
.name = "printbench",
.description = "Run a printing benchmark.",
.func = cmd_printbench,
.argc = 0,
};
#endif
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 = "<command> Describe specified command.",
.help = desc_help,
.func = cmd_desc,
.argc = 1,
.argv = &desc_argv,
.hints_enum = cmdtab_enum
};
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 = "<symbol> Return symbol address.",
.func = cmd_symaddr,
.argc = 1,
.argv = &symaddr_argv,
.hints_enum = symtab_hints_enum,
};
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 = "<addr> <value> Set 4B memory location to a value.",
.func = cmd_set4,
.argc = 2,
.argv = set4_argv
};
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 = "<function> Call function().",
.func = cmd_call0,
.argc = 1,
.argv = &call0_argv,
.hints_enum = symtab_hints_enum
};
static int cmd_mcall0(cmd_arg_t *argv);
static cmd_arg_t mcall0_argv = {
.type = ARG_TYPE_STRING,
.buffer = call0_buf,
.len = sizeof(call0_buf)
};
static cmd_info_t mcall0_info = {
.name = "mcall0",
.description = "<function> Call function() on each CPU.",
.func = cmd_mcall0,
.argc = 1,
.argv = &mcall0_argv,
.hints_enum = symtab_hints_enum
};
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 = "<function> <arg1> Call function(arg1).",
.func = cmd_call1,
.argc = 2,
.argv = call1_argv,
.hints_enum = symtab_hints_enum
};
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 = "<function> <arg1> <arg2> Call function(arg1, arg2).",
.func = cmd_call2,
.argc = 3,
.argv = call2_argv,
.hints_enum = symtab_hints_enum
};
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 = "<function> <arg1> <arg2> <arg3> Call function(arg1, arg2, arg3).",
.func = cmd_call3,
.argc = 4,
.argv = call3_argv,
.hints_enum = symtab_hints_enum
};
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
};
static int cmd_physmem(cmd_arg_t *argv);
cmd_info_t physmem_info = {
.name = "physmem",
.description = "Print physical memory configuration.",
.help = NULL,
.func = cmd_physmem,
.argc = 0,
.argv = NULL
};
static int cmd_tlb(cmd_arg_t *argv);
cmd_info_t tlb_info = {
.name = "tlb",
.description = "Print TLB of the current CPU.",
.help = NULL,
.func = cmd_tlb,
.argc = 0,
.argv = NULL
};
static char flag_buf[MAX_CMDLINE + 1];
static int cmd_threads(cmd_arg_t *argv);
static cmd_arg_t threads_argv = {
.type = ARG_TYPE_STRING_OPTIONAL,
.buffer = flag_buf,
.len = sizeof(flag_buf)
};
static cmd_info_t threads_info = {
.name = "threads",
.description = "List all threads (use -a for additional information).",
.func = cmd_threads,
.argc = 1,
.argv = &threads_argv
};
static int cmd_tasks(cmd_arg_t *argv);
static cmd_arg_t tasks_argv = {
.type = ARG_TYPE_STRING_OPTIONAL,
.buffer = flag_buf,
.len = sizeof(flag_buf)
};
static cmd_info_t tasks_info = {
.name = "tasks",
.description = "List all tasks (use -a for additional information).",
.func = cmd_tasks,
.argc = 1,
.argv = &tasks_argv
};
#ifdef CONFIG_UDEBUG
static int cmd_btrace(cmd_arg_t *argv);
static cmd_arg_t btrace_argv = {
.type = ARG_TYPE_INT,
};
static cmd_info_t btrace_info = {
.name = "btrace",
.description = "<threadid> Show thread stack trace.",
.func = cmd_btrace,
.argc = 1,
.argv = &btrace_argv
};
#endif
static int cmd_sched(cmd_arg_t *argv);
static cmd_info_t sched_info = {
.name = "scheduler",
.description = "Show scheduler information.",
.func = cmd_sched,
.argc = 0
};
static int cmd_caches(cmd_arg_t *argv);
static cmd_info_t caches_info = {
.name = "caches",
.description = "List slab caches.",
.func = cmd_caches,
.argc = 0
};
static int cmd_sysinfo(cmd_arg_t *argv);
static cmd_info_t sysinfo_info = {
.name = "sysinfo",
.description = "Dump sysinfo.",
.func = cmd_sysinfo,
.argc = 0
};
static int cmd_zones(cmd_arg_t *argv);
static cmd_info_t zones_info = {
.name = "zones",
.description = "List memory zones.",
.func = cmd_zones,
.argc = 0
};
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 = "<zone> Show memory zone structure.",
.func = cmd_zone,
.argc = 1,
.argv = &zone_argv
};
static int cmd_ipc(cmd_arg_t *argv);
static cmd_arg_t ipc_argv = {
.type = ARG_TYPE_INT,
};
static cmd_info_t ipc_info = {
.name = "ipc",
.description = "<taskid> Show IPC information of a task.",
.func = cmd_ipc,
.argc = 1,
.argv = &ipc_argv
};
static int cmd_kill(cmd_arg_t *argv);
static cmd_arg_t kill_argv = {
.type = ARG_TYPE_INT,
};
static cmd_info_t kill_info = {
.name = "kill",
.description = "<taskid> Kill a task.",
.func = cmd_kill,
.argc = 1,
.argv = &kill_argv
};
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
};
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,
&mcall0_info,
&caches_info,
&call1_info,
&call2_info,
&call3_info,
&continue_info,
&cpus_info,
&desc_info,
&halt_info,
&help_info,
&ipc_info,
&kill_info,
&physmem_info,
&reboot_info,
&sched_info,
&set4_info,
&symaddr_info,
&sysinfo_info,
&tasks_info,
&threads_info,
&tlb_info,
&uptime_info,
&version_info,
&zones_info,
&zone_info,
#ifdef CONFIG_TEST
&test_info,
&bench_info,
&printbench_info,
#endif
#ifdef CONFIG_UDEBUG
&btrace_info,
#endif
&pio_read_8_info,
&pio_read_16_info,
&pio_read_32_info,
&pio_write_8_info,
&pio_write_16_info,
&pio_write_32_info,
NULL
};
void cmd_initialize(cmd_info_t *cmd)
{
spinlock_initialize(&cmd->lock, "cmd.lock");
link_initialize(&cmd->link);
}
void cmd_init(void)
{
unsigned int i;
for (i = 0; basic_commands[i]; i++) {
cmd_initialize(basic_commands[i]);
}
for (i = 0; basic_commands[i]; i++) {
if (!cmd_register(basic_commands[i])) {
log(LF_OTHER, LVL_ERROR,
"Cannot register command %s",
basic_commands[i]->name);
}
}
}
int cmd_help(cmd_arg_t *argv)
{
spinlock_lock(&cmd_lock);
size_t len = 0;
list_foreach(cmd_list, link, cmd_info_t, hlp) {
spinlock_lock(&hlp->lock);
if (str_length(hlp->name) > len)
len = str_length(hlp->name);
spinlock_unlock(&hlp->lock);
}
unsigned int _len = (unsigned int) len;
if ((_len != len) || (((int) _len) < 0)) {
log(LF_OTHER, LVL_ERROR, "Command length overflow");
return 1;
}
list_foreach(cmd_list, link, cmd_info_t, hlp) {
spinlock_lock(&hlp->lock);
printf("%-*s %s\n", _len, hlp->name, hlp->description);
spinlock_unlock(&hlp->lock);
}
spinlock_unlock(&cmd_lock);
return 1;
}
static int cmd_pio_read_8(cmd_arg_t *argv)
{
uint8_t *ptr = NULL;
#ifdef IO_SPACE_BOUNDARY
if ((void *) argv->intval < IO_SPACE_BOUNDARY)
ptr = (void *) argv[0].intval;
else
#endif
ptr = (uint8_t *) km_map(argv[0].intval, sizeof(uint8_t),
PAGE_SIZE, PAGE_NOT_CACHEABLE);
const uint8_t val = pio_read_8(ptr);
printf("read %" PRIxn ": %" PRIx8 "\n", argv[0].intval, val);
#ifdef IO_SPACE_BOUNDARY
if ((void *) argv->intval < IO_SPACE_BOUNDARY)
return 1;
#endif
km_unmap((uintptr_t) ptr, sizeof(uint8_t));
return 1;
}
static int cmd_pio_read_16(cmd_arg_t *argv)
{
uint16_t *ptr = NULL;
#ifdef IO_SPACE_BOUNDARY
if ((void *) argv->intval < IO_SPACE_BOUNDARY)
ptr = (void *) argv[0].intval;
else
#endif
ptr = (uint16_t *) km_map(argv[0].intval, sizeof(uint16_t),
PAGE_SIZE, PAGE_NOT_CACHEABLE);
const uint16_t val = pio_read_16(ptr);
printf("read %" PRIxn ": %" PRIx16 "\n", argv[0].intval, val);
#ifdef IO_SPACE_BOUNDARY
if ((void *) argv->intval < IO_SPACE_BOUNDARY)
return 1;
#endif
km_unmap((uintptr_t) ptr, sizeof(uint16_t));
return 1;
}
static int cmd_pio_read_32(cmd_arg_t *argv)
{
uint32_t *ptr = NULL;
#ifdef IO_SPACE_BOUNDARY
if ((void *) argv->intval < IO_SPACE_BOUNDARY)
ptr = (void *) argv[0].intval;
else
#endif
ptr = (uint32_t *) km_map(argv[0].intval, sizeof(uint32_t),
PAGE_SIZE, PAGE_NOT_CACHEABLE);
const uint32_t val = pio_read_32(ptr);
printf("read %" PRIxn ": %" PRIx32 "\n", argv[0].intval, val);
#ifdef IO_SPACE_BOUNDARY
if ((void *) argv->intval < IO_SPACE_BOUNDARY)
return 1;
#endif
km_unmap((uintptr_t) ptr, sizeof(uint32_t));
return 1;
}
static int cmd_pio_write_8(cmd_arg_t *argv)
{
uint8_t *ptr = NULL;
#ifdef IO_SPACE_BOUNDARY
if ((void *) argv->intval < IO_SPACE_BOUNDARY)
ptr = (void *) argv[0].intval;
else
#endif
ptr = (uint8_t *) km_map(argv[0].intval, sizeof(uint8_t),
PAGE_SIZE, PAGE_NOT_CACHEABLE);
printf("write %" PRIxn ": %" PRIx8 "\n", argv[0].intval,
(uint8_t) argv[1].intval);
pio_write_8(ptr, (uint8_t) argv[1].intval);
#ifdef IO_SPACE_BOUNDARY
if ((void *) argv->intval < IO_SPACE_BOUNDARY)
return 1;
#endif
km_unmap((uintptr_t) ptr, sizeof(uint8_t));
return 1;
}
static int cmd_pio_write_16(cmd_arg_t *argv)
{
uint16_t *ptr = NULL;
#ifdef IO_SPACE_BOUNDARY
if ((void *) argv->intval < IO_SPACE_BOUNDARY)
ptr = (void *) argv[0].intval;
else
#endif
ptr = (uint16_t *) km_map(argv[0].intval, sizeof(uint16_t),
PAGE_SIZE, PAGE_NOT_CACHEABLE);
printf("write %" PRIxn ": %" PRIx16 "\n", argv[0].intval,
(uint16_t) argv[1].intval);
pio_write_16(ptr, (uint16_t) argv[1].intval);
#ifdef IO_SPACE_BOUNDARY
if ((void *) argv->intval < IO_SPACE_BOUNDARY)
return 1;
#endif
km_unmap((uintptr_t) ptr, sizeof(uint16_t));
return 1;
}
static int cmd_pio_write_32(cmd_arg_t *argv)
{
uint32_t *ptr = NULL;
#ifdef IO_SPACE_BOUNDARY
if ((void *) argv->intval < IO_SPACE_BOUNDARY)
ptr = (void *) argv[0].intval;
else
#endif
ptr = (uint32_t *) km_map(argv[0].intval, sizeof(uint32_t),
PAGE_SIZE, PAGE_NOT_CACHEABLE);
printf("write %" PRIxn ": %" PRIx32 "\n", argv[0].intval,
(uint32_t) argv[1].intval);
pio_write_32(ptr, (uint32_t) argv[1].intval);
#ifdef IO_SPACE_BOUNDARY
if ((void *) argv->intval < IO_SPACE_BOUNDARY)
return 1;
#endif
km_unmap((uintptr_t) ptr, sizeof(uint32_t));
return 1;
}
int cmd_reboot(cmd_arg_t *argv)
{
reboot();
return 1;
}
int cmd_uptime(cmd_arg_t *argv)
{
assert(uptime);
sysarg_t sec = uptime->seconds1;
printf("Up %" PRIun " days, %" PRIun " hours, %" PRIun " minutes, %" PRIun " seconds\n",
sec / 86400, (sec % 86400) / 3600, (sec % 3600) / 60, sec % 60);
return 1;
}
int cmd_desc(cmd_arg_t *argv)
{
spinlock_lock(&cmd_lock);
list_foreach(cmd_list, link, cmd_info_t, hlp) {
spinlock_lock(&hlp->lock);
if (str_lcmp(hlp->name, (const char *) argv->buffer, str_length(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;
}
int cmd_symaddr(cmd_arg_t *argv)
{
symtab_print_search((char *) argv->buffer);
return 1;
}
int cmd_call0(cmd_arg_t *argv)
{
uintptr_t symaddr;
char *symbol;
sysarg_t (*fnc)(void);
fncptr_t fptr;
errno_t rc;
symbol = (char *) argv->buffer;
rc = symtab_addr_lookup(symbol, &symaddr);
if (rc == ENOENT)
printf("Symbol %s not found.\n", symbol);
else if (rc == EOVERFLOW) {
symtab_print_search(symbol);
printf("Duplicate symbol, be more specific.\n");
} else if (rc == EOK) {
ipl_t ipl;
ipl = interrupts_disable();
fnc = (sysarg_t (*)(void)) arch_construct_function(&fptr,
(void *) symaddr, (void *) cmd_call0);
printf("Calling %s() (%p)\n", symbol, (void *) symaddr);
printf("Result: %#" PRIxn "\n", fnc());
interrupts_restore(ipl);
} else {
printf("No symbol information available.\n");
}
return 1;
}
int cmd_mcall0(cmd_arg_t *argv)
{
unsigned int i;
for (i = 0; i < config.cpu_count; i++) {
if (!cpus[i].active)
continue;
thread_t *thread;
if ((thread = thread_create((void (*)(void *)) cmd_call0,
(void *) argv, TASK, THREAD_FLAG_NONE, "call0"))) {
printf("cpu%u: ", i);
thread_wire(thread, &cpus[i]);
thread_start(thread);
thread_join(thread);
} else
printf("Unable to create thread for cpu%u\n", i);
}
return 1;
}
int cmd_call1(cmd_arg_t *argv)
{
uintptr_t symaddr;
char *symbol;
sysarg_t (*fnc)(sysarg_t, ...);
sysarg_t arg1 = argv[1].intval;
fncptr_t fptr;
errno_t rc;
symbol = (char *) argv->buffer;
rc = symtab_addr_lookup(symbol, &symaddr);
if (rc == ENOENT) {
printf("Symbol %s not found.\n", symbol);
} else if (rc == EOVERFLOW) {
symtab_print_search(symbol);
printf("Duplicate symbol, be more specific.\n");
} else if (rc == EOK) {
ipl_t ipl;
ipl = interrupts_disable();
fnc = (sysarg_t (*)(sysarg_t, ...))
arch_construct_function(&fptr, (void *) symaddr,
(void *) cmd_call1);
printf("Calling f(%#" PRIxn "): %p: %s\n", arg1,
(void *) symaddr, symbol);
printf("Result: %#" PRIxn "\n", fnc(arg1));
interrupts_restore(ipl);
} else {
printf("No symbol information available.\n");
}
return 1;
}
int cmd_call2(cmd_arg_t *argv)
{
uintptr_t symaddr;
char *symbol;
sysarg_t (*fnc)(sysarg_t, sysarg_t, ...);
sysarg_t arg1 = argv[1].intval;
sysarg_t arg2 = argv[2].intval;
fncptr_t fptr;
errno_t rc;
symbol = (char *) argv->buffer;
rc = symtab_addr_lookup(symbol, &symaddr);
if (rc == ENOENT) {
printf("Symbol %s not found.\n", symbol);
} else if (rc == EOVERFLOW) {
symtab_print_search(symbol);
printf("Duplicate symbol, be more specific.\n");
} else if (rc == EOK) {
ipl_t ipl;
ipl = interrupts_disable();
fnc = (sysarg_t (*)(sysarg_t, sysarg_t, ...))
arch_construct_function(&fptr, (void *) symaddr,
(void *) cmd_call2);
printf("Calling f(%#" PRIxn ", %#" PRIxn "): %p: %s\n",
arg1, arg2, (void *) symaddr, symbol);
printf("Result: %#" PRIxn "\n", fnc(arg1, arg2));
interrupts_restore(ipl);
} else {
printf("No symbol information available.\n");
}
return 1;
}
int cmd_call3(cmd_arg_t *argv)
{
uintptr_t symaddr;
char *symbol;
sysarg_t (*fnc)(sysarg_t, sysarg_t, sysarg_t, ...);
sysarg_t arg1 = argv[1].intval;
sysarg_t arg2 = argv[2].intval;
sysarg_t arg3 = argv[3].intval;
fncptr_t fptr;
errno_t rc;
symbol = (char *) argv->buffer;
rc = symtab_addr_lookup(symbol, &symaddr);
if (rc == ENOENT) {
printf("Symbol %s not found.\n", symbol);
} else if (rc == EOVERFLOW) {
symtab_print_search(symbol);
printf("Duplicate symbol, be more specific.\n");
} else if (rc == EOK) {
ipl_t ipl;
ipl = interrupts_disable();
fnc = (sysarg_t (*)(sysarg_t, sysarg_t, sysarg_t, ...))
arch_construct_function(&fptr, (void *) symaddr,
(void *) cmd_call3);
printf("Calling f(%#" PRIxn ",%#" PRIxn ", %#" PRIxn "): %p: %s\n",
arg1, arg2, arg3, (void *) symaddr, symbol);
printf("Result: %#" PRIxn "\n", fnc(arg1, arg2, arg3));
interrupts_restore(ipl);
} else {
printf("No symbol information available.\n");
}
return 1;
}
void desc_help(void)
{
printf("Syntax: describe command_name\n");
}
int cmd_halt(cmd_arg_t *argv)
{
halt();
return 1;
}
int cmd_tlb(cmd_arg_t *argv)
{
tlb_print();
return 1;
}
int cmd_physmem(cmd_arg_t *argv)
{
physmem_print();
return 1;
}
int cmd_set4(cmd_arg_t *argv)
{
uintptr_t addr = 0;
uint32_t arg1 = argv[1].intval;
bool pointer = false;
errno_t rc;
if (((char *) argv->buffer)[0] == '*') {
rc = symtab_addr_lookup((char *) argv->buffer + 1, &addr);
pointer = true;
} else if (((char *) argv->buffer)[0] >= '0' &&
((char *) argv->buffer)[0] <= '9') {
uint64_t value;
rc = str_uint64_t((char *) argv->buffer, NULL, 0, true, &value);
if (rc == EOK)
addr = (uintptr_t) value;
} else
rc = symtab_addr_lookup((char *) argv->buffer, &addr);
if (rc == ENOENT)
printf("Symbol %s not found.\n", (char *) argv->buffer);
else if (rc == EINVAL)
printf("Invalid address.\n");
else if (rc == EOVERFLOW) {
symtab_print_search((char *) argv->buffer);
printf("Duplicate symbol (be more specific) or address overflow.\n");
} else if (rc == EOK) {
if (pointer)
addr = *(uintptr_t *) addr;
printf("Writing %#" PRIx32 " -> %p\n", arg1, (void *) addr);
*(uint32_t *) addr = arg1;
} else
printf("No symbol information available.\n");
return 1;
}
int cmd_caches(cmd_arg_t *argv)
{
slab_print_list();
return 1;
}
int cmd_sysinfo(cmd_arg_t *argv)
{
sysinfo_dump(NULL);
return 1;
}
int cmd_threads(cmd_arg_t *argv)
{
if (str_cmp(flag_buf, "-a") == 0)
thread_print_list(true);
else if (str_cmp(flag_buf, "") == 0)
thread_print_list(false);
else
printf("Unknown argument \"%s\".\n", flag_buf);
return 1;
}
int cmd_tasks(cmd_arg_t *argv)
{
if (str_cmp(flag_buf, "-a") == 0)
task_print_list(true);
else if (str_cmp(flag_buf, "") == 0)
task_print_list(false);
else
printf("Unknown argument \"%s\".\n", flag_buf);
return 1;
}
#ifdef CONFIG_UDEBUG
int cmd_btrace(cmd_arg_t *argv)
{
thread_stack_trace(argv[0].intval);
return 1;
}
#endif
int cmd_sched(cmd_arg_t *argv)
{
sched_print_list();
return 1;
}
int cmd_zones(cmd_arg_t *argv)
{
zones_print_list();
return 1;
}
int cmd_zone(cmd_arg_t *argv)
{
zone_print_one(argv[0].intval);
return 1;
}
int cmd_ipc(cmd_arg_t *argv)
{
ipc_print_task(argv[0].intval);
return 1;
}
int cmd_kill(cmd_arg_t *argv)
{
if (task_kill(argv[0].intval) != EOK)
return 0;
return 1;
}
int cmd_cpus(cmd_arg_t *argv)
{
cpu_list();
return 1;
}
int cmd_version(cmd_arg_t *argv)
{
version_print();
return 1;
}
int cmd_continue(cmd_arg_t *argv)
{
printf("The kernel will now relinquish the console.\n");
release_console();
indev_pop_character(stdin);
return 1;
}
#ifdef CONFIG_TEST
static bool run_test(const test_t *test)
{
printf("%s (%s)\n", test->name, test->desc);
irq_spinlock_lock(&TASK->lock, true);
uint64_t ucycles0, kcycles0;
task_get_accounting(TASK, &ucycles0, &kcycles0);
irq_spinlock_unlock(&TASK->lock, true);
test_quiet = false;
const char *ret = test->entry();
uint64_t ucycles1, kcycles1;
irq_spinlock_lock(&TASK->lock, true);
task_get_accounting(TASK, &ucycles1, &kcycles1);
irq_spinlock_unlock(&TASK->lock, true);
uint64_t ucycles, kcycles;
char usuffix, ksuffix;
order_suffix(ucycles1 - ucycles0, &ucycles, &usuffix);
order_suffix(kcycles1 - kcycles0, &kcycles, &ksuffix);
printf("Time: %" PRIu64 "%c user cycles, %" PRIu64 "%c kernel cycles\n",
ucycles, usuffix, kcycles, ksuffix);
if (ret == NULL) {
printf("Test passed\n");
return true;
}
printf("%s\n", ret);
return false;
}
static bool run_bench(const test_t *test, const uint32_t cnt)
{
uint32_t i;
bool ret = true;
uint64_t ucycles, kcycles;
char usuffix, ksuffix;
if (cnt < 1)
return true;
uint64_t *data = (uint64_t *) malloc(sizeof(uint64_t) * cnt);
if (data == NULL) {
printf("Error allocating memory for statistics\n");
return false;
}
for (i = 0; i < cnt; i++) {
printf("%s (%u/%u) ... ", test->name, i + 1, cnt);
irq_spinlock_lock(&TASK->lock, true);
uint64_t ucycles0, kcycles0;
task_get_accounting(TASK, &ucycles0, &kcycles0);
irq_spinlock_unlock(&TASK->lock, true);
test_quiet = true;
const char *test_ret = test->entry();
irq_spinlock_lock(&TASK->lock, true);
uint64_t ucycles1, kcycles1;
task_get_accounting(TASK, &ucycles1, &kcycles1);
irq_spinlock_unlock(&TASK->lock, true);
if (test_ret != NULL) {
printf("%s\n", test_ret);
ret = false;
break;
}
data[i] = ucycles1 - ucycles0 + kcycles1 - kcycles0;
order_suffix(ucycles1 - ucycles0, &ucycles, &usuffix);
order_suffix(kcycles1 - kcycles0, &kcycles, &ksuffix);
printf("OK (%" PRIu64 "%c user cycles, %" PRIu64 "%c kernel cycles)\n",
ucycles, usuffix, kcycles, ksuffix);
}
if (ret) {
printf("\n");
uint64_t sum = 0;
for (i = 0; i < cnt; i++) {
sum += data[i];
}
order_suffix(sum / (uint64_t) cnt, &ucycles, &usuffix);
printf("Average\t\t%" PRIu64 "%c\n", ucycles, usuffix);
}
free(data);
return ret;
}
static void list_tests(void)
{
size_t len = 0;
test_t *test;
for (test = tests; test->name != NULL; test++) {
if (str_length(test->name) > len)
len = str_length(test->name);
}
unsigned int _len = (unsigned int) len;
if ((_len != len) || (((int) _len) < 0)) {
printf("Command length overflow\n");
return;
}
for (test = tests; test->name != NULL; test++)
printf("%-*s %s%s\n", _len, test->name, test->desc,
(test->safe ? "" : " (unsafe)"));
printf("%-*s Run all safe tests\n", _len, "*");
}
int cmd_test(cmd_arg_t *argv)
{
test_t *test;
if (str_cmp((char *) argv->buffer, "*") == 0) {
for (test = tests; test->name != NULL; test++) {
if (test->safe) {
printf("\n");
if (!run_test(test))
break;
}
}
} else if (str_cmp((char *) argv->buffer, "") != 0) {
bool fnd = false;
for (test = tests; test->name != NULL; test++) {
if (str_cmp(test->name, (char *) argv->buffer) == 0) {
fnd = true;
run_test(test);
break;
}
}
if (!fnd)
printf("Unknown test\n");
} else
list_tests();
return 1;
}
int cmd_bench(cmd_arg_t *argv)
{
test_t *test;
uint32_t cnt = argv[1].intval;
if (str_cmp((char *) argv->buffer, "*") == 0) {
for (test = tests; test->name != NULL; test++) {
if (test->safe) {
if (!run_bench(test, cnt))
break;
}
}
} else {
bool fnd = false;
for (test = tests; test->name != NULL; test++) {
if (str_cmp(test->name, (char *) argv->buffer) == 0) {
fnd = true;
if (test->safe)
run_bench(test, cnt);
else
printf("Unsafe test\n");
break;
}
}
if (!fnd)
printf("Unknown test\n");
}
return 1;
}
int cmd_printbench(cmd_arg_t *argv)
{
int cnt = 20;
uint64_t *data = malloc(sizeof(uint64_t) * cnt);
if (data == NULL) {
printf("Error allocating memory for statistics\n");
return false;
}
for (int i = 0; i < cnt; i++) {
irq_spinlock_lock(&TASK->lock, true);
uint64_t ucycles0, kcycles0;
task_get_accounting(TASK, &ucycles0, &kcycles0);
irq_spinlock_unlock(&TASK->lock, true);
for (int j = 0; j < 20; j++) {
printf("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ěščřžýáíéú!@#$%%^&*(){}+\n");
printf("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ěščřžýáíéú!@#$%%^&*(){}+abcdefghijklmnopqrstuvwxyz\n");
printf("0123456789ěščřžýáíéú!@#$%%^&*(){}+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\n");
}
irq_spinlock_lock(&TASK->lock, true);
uint64_t ucycles1, kcycles1;
task_get_accounting(TASK, &ucycles1, &kcycles1);
irq_spinlock_unlock(&TASK->lock, true);
data[i] = ucycles1 - ucycles0 + kcycles1 - kcycles0;
}
printf("\n");
uint64_t cycles;
char suffix;
uint64_t sum = 0;
for (int i = 0; i < cnt; i++) {
sum += data[i];
}
order_suffix(sum / (uint64_t) cnt, &cycles, &suffix);
printf("Average\t\t%" PRIu64 "%c\n", cycles, suffix);
free(data);
return true;
}
#endif
HelenOS homepage, sources at GitHub