~martin-decky/helenos/rcu

« back to all changes in this revision

Viewing changes to kernel/generic/src/console/cmd.c

  • Committer: Martin Decky
  • Date: 2009-08-04 11:19:19 UTC
  • Revision ID: martin@uranus.dsrg.hide.ms.mff.cuni.cz-20090804111919-evyclddlr3v5lhmp
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2005 Jakub Jermar
 
3
 * All rights reserved.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 *
 
9
 * - Redistributions of source code must retain the above copyright
 
10
 *   notice, this list of conditions and the following disclaimer.
 
11
 * - Redistributions in binary form must reproduce the above copyright
 
12
 *   notice, this list of conditions and the following disclaimer in the
 
13
 *   documentation and/or other materials provided with the distribution.
 
14
 * - The name of the author may not be used to endorse or promote products
 
15
 *   derived from this software without specific prior written permission.
 
16
 *
 
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
27
 */
 
28
 
 
29
/** @addtogroup genericconsole
 
30
 * @{
 
31
 */
 
32
 
 
33
/**
 
34
 * @file  cmd.c
 
35
 * @brief Kernel console command wrappers.
 
36
 *
 
37
 * This file is meant to contain all wrapper functions for
 
38
 * all kconsole commands. The point is in separating
 
39
 * kconsole specific wrappers from kconsole-unaware functions
 
40
 * from other subsystems.
 
41
 */
 
42
 
 
43
#include <console/cmd.h>
 
44
#include <console/console.h>
 
45
#include <console/kconsole.h>
 
46
#include <print.h>
 
47
#include <panic.h>
 
48
#include <arch/types.h>
 
49
#include <adt/list.h>
 
50
#include <arch.h>
 
51
#include <config.h>
 
52
#include <func.h>
 
53
#include <string.h>
 
54
#include <macros.h>
 
55
#include <debug.h>
 
56
#include <cpu.h>
 
57
#include <mm/tlb.h>
 
58
#include <arch/mm/tlb.h>
 
59
#include <mm/frame.h>
 
60
#include <main/version.h>
 
61
#include <mm/slab.h>
 
62
#include <proc/scheduler.h>
 
63
#include <proc/thread.h>
 
64
#include <proc/task.h>
 
65
#include <ipc/ipc.h>
 
66
#include <ipc/irq.h>
 
67
#include <ipc/event.h>
 
68
#include <symtab.h>
 
69
#include <errno.h>
 
70
 
 
71
#ifdef CONFIG_TEST
 
72
#include <test.h>
 
73
#endif
 
74
 
 
75
/* Data and methods for 'help' command. */
 
76
static int cmd_help(cmd_arg_t *argv);
 
77
static cmd_info_t help_info = {
 
78
        .name = "help",
 
79
        .description = "List of supported commands.",
 
80
        .func = cmd_help,
 
81
        .argc = 0
 
82
};
 
83
 
 
84
static int cmd_reboot(cmd_arg_t *argv);
 
85
static cmd_info_t reboot_info = {
 
86
        .name = "reboot",
 
87
        .description = "Reboot.",
 
88
        .func = cmd_reboot,
 
89
        .argc = 0
 
90
};
 
91
 
 
92
static int cmd_uptime(cmd_arg_t *argv);
 
93
static cmd_info_t uptime_info = {
 
94
        .name = "uptime",
 
95
        .description = "Print uptime information.",
 
96
        .func = cmd_uptime,
 
97
        .argc = 0
 
98
};
 
99
 
 
100
static int cmd_continue(cmd_arg_t *argv);
 
101
static cmd_info_t continue_info = {
 
102
        .name = "continue",
 
103
        .description = "Return console back to userspace.",
 
104
        .func = cmd_continue,
 
105
        .argc = 0
 
106
};
 
107
 
 
108
#ifdef CONFIG_TEST
 
109
static int cmd_tests(cmd_arg_t *argv);
 
110
static cmd_info_t tests_info = {
 
111
        .name = "tests",
 
112
        .description = "Print available kernel tests.",
 
113
        .func = cmd_tests,
 
114
        .argc = 0
 
115
};
 
116
 
 
117
static char test_buf[MAX_CMDLINE + 1];
 
118
static int cmd_test(cmd_arg_t *argv);
 
119
static cmd_arg_t test_argv[] = {
 
120
        {
 
121
                .type = ARG_TYPE_STRING,
 
122
                .buffer = test_buf,
 
123
                .len = sizeof(test_buf)
 
124
        }
 
125
};
 
126
static cmd_info_t test_info = {
 
127
        .name = "test",
 
128
        .description = "Run kernel test.",
 
129
        .func = cmd_test,
 
130
        .argc = 1,
 
131
        .argv = test_argv
 
132
};
 
133
 
 
134
static int cmd_bench(cmd_arg_t *argv);
 
135
static cmd_arg_t bench_argv[] = {
 
136
        {
 
137
                .type = ARG_TYPE_STRING,
 
138
                .buffer = test_buf,
 
139
                .len = sizeof(test_buf)
 
140
        },
 
141
        {
 
142
                .type = ARG_TYPE_INT,
 
143
        }
 
144
};
 
145
static cmd_info_t bench_info = {
 
146
        .name = "bench",
 
147
        .description = "Run kernel test as benchmark.",
 
148
        .func = cmd_bench,
 
149
        .argc = 2,
 
150
        .argv = bench_argv
 
151
};
 
152
#endif
 
153
 
 
154
/* Data and methods for 'description' command. */
 
155
static int cmd_desc(cmd_arg_t *argv);
 
156
static void desc_help(void);
 
157
static char desc_buf[MAX_CMDLINE+1];
 
158
static cmd_arg_t desc_argv = {
 
159
        .type = ARG_TYPE_STRING,
 
160
        .buffer = desc_buf,
 
161
        .len = sizeof(desc_buf)
 
162
};
 
163
static cmd_info_t desc_info = {
 
164
        .name = "describe",
 
165
        .description = "Describe specified command.",
 
166
        .help = desc_help,
 
167
        .func = cmd_desc,
 
168
        .argc = 1,
 
169
        .argv = &desc_argv
 
170
};
 
171
 
 
172
/* Data and methods for 'symaddr' command. */
 
173
static int cmd_symaddr(cmd_arg_t *argv);
 
174
static char symaddr_buf[MAX_CMDLINE+1];
 
175
static cmd_arg_t symaddr_argv = {
 
176
        .type = ARG_TYPE_STRING,
 
177
        .buffer = symaddr_buf,
 
178
        .len = sizeof(symaddr_buf)
 
179
};
 
180
static cmd_info_t symaddr_info = {
 
181
        .name = "symaddr",
 
182
        .description = "Return symbol address.",
 
183
        .func = cmd_symaddr,
 
184
        .argc = 1,
 
185
        .argv = &symaddr_argv
 
186
};
 
187
 
 
188
static char set_buf[MAX_CMDLINE+1];
 
189
static int cmd_set4(cmd_arg_t *argv);
 
190
static cmd_arg_t set4_argv[] = {
 
191
        {
 
192
                .type = ARG_TYPE_STRING,
 
193
                .buffer = set_buf,
 
194
                .len = sizeof(set_buf)
 
195
        },
 
196
        { 
 
197
                .type = ARG_TYPE_INT
 
198
        }
 
199
};
 
200
static cmd_info_t set4_info = {
 
201
        .name = "set4",
 
202
        .description = "set <dest_addr> <value> - 4byte version",
 
203
        .func = cmd_set4,
 
204
        .argc = 2,
 
205
        .argv = set4_argv
 
206
};
 
207
 
 
208
/* Data and methods for 'call0' command. */
 
209
static char call0_buf[MAX_CMDLINE + 1];
 
210
static char carg1_buf[MAX_CMDLINE + 1];
 
211
static char carg2_buf[MAX_CMDLINE + 1];
 
212
static char carg3_buf[MAX_CMDLINE + 1];
 
213
 
 
214
static int cmd_call0(cmd_arg_t *argv);
 
215
static cmd_arg_t call0_argv = {
 
216
        .type = ARG_TYPE_STRING,
 
217
        .buffer = call0_buf,
 
218
        .len = sizeof(call0_buf)
 
219
};
 
220
static cmd_info_t call0_info = {
 
221
        .name = "call0",
 
222
        .description = "call0 <function> -> call function().",
 
223
        .func = cmd_call0,
 
224
        .argc = 1,
 
225
        .argv = &call0_argv
 
226
};
 
227
 
 
228
/* Data and methods for 'mcall0' command. */
 
229
static int cmd_mcall0(cmd_arg_t *argv);
 
230
static cmd_arg_t mcall0_argv = {
 
231
        .type = ARG_TYPE_STRING,
 
232
        .buffer = call0_buf,
 
233
        .len = sizeof(call0_buf)
 
234
};
 
235
static cmd_info_t mcall0_info = {
 
236
        .name = "mcall0",
 
237
        .description = "mcall0 <function> -> call function() on each CPU.",
 
238
        .func = cmd_mcall0,
 
239
        .argc = 1,
 
240
        .argv = &mcall0_argv
 
241
};
 
242
 
 
243
/* Data and methods for 'call1' command. */
 
244
static int cmd_call1(cmd_arg_t *argv);
 
245
static cmd_arg_t call1_argv[] = {
 
246
        {
 
247
                .type = ARG_TYPE_STRING,
 
248
                .buffer = call0_buf,
 
249
                .len = sizeof(call0_buf)
 
250
        },
 
251
        { 
 
252
                .type = ARG_TYPE_VAR,
 
253
                .buffer = carg1_buf,
 
254
                .len = sizeof(carg1_buf)
 
255
        }
 
256
};
 
257
static cmd_info_t call1_info = {
 
258
        .name = "call1",
 
259
        .description = "call1 <function> <arg1> -> call function(arg1).",
 
260
        .func = cmd_call1,
 
261
        .argc = 2,
 
262
        .argv = call1_argv
 
263
};
 
264
 
 
265
/* Data and methods for 'call2' command. */
 
266
static int cmd_call2(cmd_arg_t *argv);
 
267
static cmd_arg_t call2_argv[] = {
 
268
        {
 
269
                .type = ARG_TYPE_STRING,
 
270
                .buffer = call0_buf,
 
271
                .len = sizeof(call0_buf)
 
272
        },
 
273
        { 
 
274
                .type = ARG_TYPE_VAR,
 
275
                .buffer = carg1_buf,
 
276
                .len = sizeof(carg1_buf)
 
277
        },
 
278
        { 
 
279
                .type = ARG_TYPE_VAR,
 
280
                .buffer = carg2_buf,
 
281
                .len = sizeof(carg2_buf)
 
282
        }
 
283
};
 
284
static cmd_info_t call2_info = {
 
285
        .name = "call2",
 
286
        .description = "call2 <function> <arg1> <arg2> -> call function(arg1,arg2).",
 
287
        .func = cmd_call2,
 
288
        .argc = 3,
 
289
        .argv = call2_argv
 
290
};
 
291
 
 
292
/* Data and methods for 'call3' command. */
 
293
static int cmd_call3(cmd_arg_t *argv);
 
294
static cmd_arg_t call3_argv[] = {
 
295
        {
 
296
                .type = ARG_TYPE_STRING,
 
297
                .buffer = call0_buf,
 
298
                .len = sizeof(call0_buf)
 
299
        },
 
300
        { 
 
301
                .type = ARG_TYPE_VAR,
 
302
                .buffer = carg1_buf,
 
303
                .len = sizeof(carg1_buf)
 
304
        },
 
305
        { 
 
306
                .type = ARG_TYPE_VAR,
 
307
                .buffer = carg2_buf,
 
308
                .len = sizeof(carg2_buf)
 
309
        },
 
310
        { 
 
311
                .type = ARG_TYPE_VAR,
 
312
                .buffer = carg3_buf,
 
313
                .len = sizeof(carg3_buf)
 
314
        }
 
315
 
 
316
};
 
317
static cmd_info_t call3_info = {
 
318
        .name = "call3",
 
319
        .description = "call3 <function> <arg1> <arg2> <arg3> -> call function(arg1,arg2,arg3).",
 
320
        .func = cmd_call3,
 
321
        .argc = 4,
 
322
        .argv = call3_argv
 
323
};
 
324
 
 
325
/* Data and methods for 'halt' command. */
 
326
static int cmd_halt(cmd_arg_t *argv);
 
327
static cmd_info_t halt_info = {
 
328
        .name = "halt",
 
329
        .description = "Halt the kernel.",
 
330
        .func = cmd_halt,
 
331
        .argc = 0
 
332
};
 
333
 
 
334
/* Data and methods for 'physmem' command. */
 
335
static int cmd_physmem(cmd_arg_t *argv);
 
336
cmd_info_t physmem_info = {
 
337
        .name = "physmem",
 
338
        .description = "Print physical memory configuration.",
 
339
        .help = NULL,
 
340
        .func = cmd_physmem,
 
341
        .argc = 0,
 
342
        .argv = NULL
 
343
};
 
344
 
 
345
/* Data and methods for 'tlb' command. */
 
346
static int cmd_tlb(cmd_arg_t *argv);
 
347
cmd_info_t tlb_info = {
 
348
        .name = "tlb",
 
349
        .description = "Print TLB of current processor.",
 
350
        .help = NULL,
 
351
        .func = cmd_tlb,
 
352
        .argc = 0,
 
353
        .argv = NULL
 
354
};
 
355
 
 
356
static int cmd_threads(cmd_arg_t *argv);
 
357
static cmd_info_t threads_info = {
 
358
        .name = "threads",
 
359
        .description = "List all threads.",
 
360
        .func = cmd_threads,
 
361
        .argc = 0
 
362
};
 
363
 
 
364
static int cmd_tasks(cmd_arg_t *argv);
 
365
static cmd_info_t tasks_info = {
 
366
        .name = "tasks",
 
367
        .description = "List all tasks.",
 
368
        .func = cmd_tasks,
 
369
        .argc = 0
 
370
};
 
371
 
 
372
 
 
373
static int cmd_sched(cmd_arg_t *argv);
 
374
static cmd_info_t sched_info = {
 
375
        .name = "scheduler",
 
376
        .description = "List all scheduler information.",
 
377
        .func = cmd_sched,
 
378
        .argc = 0
 
379
};
 
380
 
 
381
static int cmd_slabs(cmd_arg_t *argv);
 
382
static cmd_info_t slabs_info = {
 
383
        .name = "slabs",
 
384
        .description = "List slab caches.",
 
385
        .func = cmd_slabs,
 
386
        .argc = 0
 
387
};
 
388
 
 
389
/* Data and methods for 'zones' command */
 
390
static int cmd_zones(cmd_arg_t *argv);
 
391
static cmd_info_t zones_info = {
 
392
        .name = "zones",
 
393
        .description = "List of memory zones.",
 
394
        .func = cmd_zones,
 
395
        .argc = 0
 
396
};
 
397
 
 
398
/* Data and methods for 'ipc' command */
 
399
static int cmd_ipc(cmd_arg_t *argv);
 
400
static cmd_arg_t ipc_argv = {
 
401
        .type = ARG_TYPE_INT,
 
402
};
 
403
static cmd_info_t ipc_info = {
 
404
        .name = "ipc",
 
405
        .description = "ipc <taskid> Show IPC information of given task.",
 
406
        .func = cmd_ipc,
 
407
        .argc = 1,
 
408
        .argv = &ipc_argv
 
409
};
 
410
 
 
411
/* Data and methods for 'zone' command */
 
412
static int cmd_zone(cmd_arg_t *argv);
 
413
static cmd_arg_t zone_argv = {
 
414
        .type = ARG_TYPE_INT,
 
415
};
 
416
 
 
417
static cmd_info_t zone_info = {
 
418
        .name = "zone",
 
419
        .description = "Show memory zone structure.",
 
420
        .func = cmd_zone,
 
421
        .argc = 1,
 
422
        .argv = &zone_argv
 
423
};
 
424
 
 
425
/* Data and methods for 'cpus' command. */
 
426
static int cmd_cpus(cmd_arg_t *argv);
 
427
cmd_info_t cpus_info = {
 
428
        .name = "cpus",
 
429
        .description = "List all processors.",
 
430
        .help = NULL,
 
431
        .func = cmd_cpus,
 
432
        .argc = 0,
 
433
        .argv = NULL
 
434
};
 
435
 
 
436
/* Data and methods for 'version' command. */
 
437
static int cmd_version(cmd_arg_t *argv);
 
438
cmd_info_t version_info = {
 
439
        .name = "version",
 
440
        .description = "Print version information.",
 
441
        .help = NULL,
 
442
        .func = cmd_version,
 
443
        .argc = 0,
 
444
        .argv = NULL
 
445
};
 
446
 
 
447
static cmd_info_t *basic_commands[] = {
 
448
        &call0_info,
 
449
        &mcall0_info,
 
450
        &call1_info,
 
451
        &call2_info,
 
452
        &call3_info,
 
453
        &continue_info,
 
454
        &cpus_info,
 
455
        &desc_info,
 
456
        &reboot_info,
 
457
        &uptime_info,
 
458
        &halt_info,
 
459
        &help_info,
 
460
        &ipc_info,
 
461
        &set4_info,
 
462
        &slabs_info,
 
463
        &symaddr_info,
 
464
        &sched_info,
 
465
        &threads_info,
 
466
        &tasks_info,
 
467
        &physmem_info,
 
468
        &tlb_info,
 
469
        &version_info,
 
470
        &zones_info,
 
471
        &zone_info,
 
472
#ifdef CONFIG_TEST
 
473
        &tests_info,
 
474
        &test_info,
 
475
        &bench_info,
 
476
#endif
 
477
        NULL
 
478
};
 
479
 
 
480
 
 
481
/** Initialize command info structure.
 
482
 *
 
483
 * @param cmd Command info structure.
 
484
 *
 
485
 */
 
486
void cmd_initialize(cmd_info_t *cmd)
 
487
{
 
488
        spinlock_initialize(&cmd->lock, "cmd");
 
489
        link_initialize(&cmd->link);
 
490
}
 
491
 
 
492
/** Initialize and register commands. */
 
493
void cmd_init(void)
 
494
{
 
495
        unsigned int i;
 
496
 
 
497
        for (i = 0; basic_commands[i]; i++) {
 
498
                cmd_initialize(basic_commands[i]);
 
499
                if (!cmd_register(basic_commands[i]))
 
500
                        printf("Cannot register command %s\n", basic_commands[i]->name);
 
501
        }
 
502
}
 
503
 
 
504
 
 
505
/** List supported commands.
 
506
 *
 
507
 * @param argv Argument vector.
 
508
 *
 
509
 * @return 0 on failure, 1 on success.
 
510
 */
 
511
int cmd_help(cmd_arg_t *argv)
 
512
{
 
513
        spinlock_lock(&cmd_lock);
 
514
        
 
515
        link_t *cur;
 
516
        size_t len = 0;
 
517
        for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
 
518
                cmd_info_t *hlp;
 
519
                hlp = list_get_instance(cur, cmd_info_t, link);
 
520
                
 
521
                spinlock_lock(&hlp->lock);
 
522
                if (str_length(hlp->name) > len)
 
523
                        len = str_length(hlp->name);
 
524
                spinlock_unlock(&hlp->lock);
 
525
        }
 
526
        
 
527
        for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
 
528
                cmd_info_t *hlp;
 
529
                hlp = list_get_instance(cur, cmd_info_t, link);
 
530
                
 
531
                spinlock_lock(&hlp->lock);
 
532
                printf("%-*s %s\n", len, hlp->name, hlp->description);
 
533
                spinlock_unlock(&hlp->lock);
 
534
        }
 
535
        
 
536
        spinlock_unlock(&cmd_lock);
 
537
        
 
538
        return 1;
 
539
}
 
540
 
 
541
 
 
542
/** Reboot the system.
 
543
 *
 
544
 * @param argv Argument vector.
 
545
 *
 
546
 * @return 0 on failure, 1 on success.
 
547
 */
 
548
int cmd_reboot(cmd_arg_t *argv)
 
549
{
 
550
        reboot();
 
551
        
 
552
        /* Not reached */
 
553
        return 1;
 
554
}
 
555
 
 
556
 
 
557
/** Print system uptime information.
 
558
 *
 
559
 * @param argv Argument vector.
 
560
 *
 
561
 * @return 0 on failure, 1 on success.
 
562
 */
 
563
int cmd_uptime(cmd_arg_t *argv)
 
564
{
 
565
        ASSERT(uptime);
 
566
        
 
567
        /* This doesn't have to be very accurate */
 
568
        unative_t sec = uptime->seconds1;
 
569
        
 
570
        printf("Up %" PRIun " days, %" PRIun " hours, %" PRIun " minutes, %" PRIun " seconds\n",
 
571
                sec / 86400, (sec % 86400) / 3600, (sec % 3600) / 60, sec % 60);
 
572
        
 
573
        return 1;
 
574
}
 
575
 
 
576
/** Describe specified command.
 
577
 *
 
578
 * @param argv Argument vector.
 
579
 *
 
580
 * @return 0 on failure, 1 on success.
 
581
 */
 
582
int cmd_desc(cmd_arg_t *argv)
 
583
{
 
584
        link_t *cur;
 
585
        
 
586
        spinlock_lock(&cmd_lock);
 
587
        
 
588
        for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
 
589
                cmd_info_t *hlp;
 
590
                
 
591
                hlp = list_get_instance(cur, cmd_info_t, link);
 
592
                spinlock_lock(&hlp->lock);
 
593
                
 
594
                if (str_lcmp(hlp->name, (const char *) argv->buffer, str_length(hlp->name)) == 0) {
 
595
                        printf("%s - %s\n", hlp->name, hlp->description);
 
596
                        if (hlp->help)
 
597
                                hlp->help();
 
598
                        spinlock_unlock(&hlp->lock);
 
599
                        break;
 
600
                }
 
601
                
 
602
                spinlock_unlock(&hlp->lock);
 
603
        }
 
604
        
 
605
        spinlock_unlock(&cmd_lock);     
 
606
        
 
607
        return 1;
 
608
}
 
609
 
 
610
/** Search symbol table */
 
611
int cmd_symaddr(cmd_arg_t *argv)
 
612
{
 
613
        symtab_print_search((char *) argv->buffer);
 
614
        
 
615
        return 1;
 
616
}
 
617
 
 
618
/** Call function with zero parameters */
 
619
int cmd_call0(cmd_arg_t *argv)
 
620
{
 
621
        uintptr_t symaddr;
 
622
        char *symbol;
 
623
        unative_t (*fnc)(void);
 
624
        fncptr_t fptr;
 
625
        int rc;
 
626
 
 
627
        symbol = (char *) argv->buffer;
 
628
        rc = symtab_addr_lookup(symbol, &symaddr);
 
629
 
 
630
        if (rc == ENOENT)
 
631
                printf("Symbol %s not found.\n", symbol);
 
632
        else if (rc == EOVERFLOW) {
 
633
                symtab_print_search(symbol);
 
634
                printf("Duplicate symbol, be more specific.\n");
 
635
        } else if (rc == EOK) {
 
636
                fnc = (unative_t (*)(void)) arch_construct_function(&fptr,
 
637
                    (void *) symaddr, (void *) cmd_call0);
 
638
                printf("Calling %s() (%p)\n", symbol, symaddr);
 
639
                printf("Result: %#" PRIxn "\n", fnc());
 
640
        } else {
 
641
                printf("No symbol information available.\n");
 
642
        }
 
643
        return 1;
 
644
}
 
645
 
 
646
/** Call function with zero parameters on each CPU */
 
647
int cmd_mcall0(cmd_arg_t *argv)
 
648
{
 
649
        /*
 
650
         * For each CPU, create a thread which will
 
651
         * call the function.
 
652
         */
 
653
        
 
654
        size_t i;
 
655
        for (i = 0; i < config.cpu_count; i++) {
 
656
                if (!cpus[i].active)
 
657
                        continue;
 
658
                
 
659
                thread_t *t;
 
660
                if ((t = thread_create((void (*)(void *)) cmd_call0, (void *) argv, TASK, THREAD_FLAG_WIRED, "call0", false))) {
 
661
                        spinlock_lock(&t->lock);
 
662
                        t->cpu = &cpus[i];
 
663
                        spinlock_unlock(&t->lock);
 
664
                        printf("cpu%u: ", i);
 
665
                        thread_ready(t);
 
666
                        thread_join(t);
 
667
                        thread_detach(t);
 
668
                } else
 
669
                        printf("Unable to create thread for cpu%u\n", i);
 
670
        }
 
671
        
 
672
        return 1;
 
673
}
 
674
 
 
675
/** Call function with one parameter */
 
676
int cmd_call1(cmd_arg_t *argv)
 
677
{
 
678
        uintptr_t symaddr;
 
679
        char *symbol;
 
680
        unative_t (*fnc)(unative_t, ...);
 
681
        unative_t arg1 = argv[1].intval;
 
682
        fncptr_t fptr;
 
683
        int rc;
 
684
 
 
685
        symbol = (char *) argv->buffer;
 
686
        rc = symtab_addr_lookup(symbol, &symaddr);
 
687
 
 
688
        if (rc == ENOENT) {
 
689
                printf("Symbol %s not found.\n", symbol);
 
690
        } else if (rc == EOVERFLOW) {
 
691
                symtab_print_search(symbol);
 
692
                printf("Duplicate symbol, be more specific.\n");
 
693
        } else if (rc == EOK) {
 
694
                fnc = (unative_t (*)(unative_t, ...)) arch_construct_function(&fptr, (void *) symaddr, (void *) cmd_call1);
 
695
                printf("Calling f(%#" PRIxn "): %p: %s\n", arg1, symaddr, symbol);
 
696
                printf("Result: %#" PRIxn "\n", fnc(arg1));
 
697
        } else {
 
698
                printf("No symbol information available.\n");
 
699
        }
 
700
 
 
701
        return 1;
 
702
}
 
703
 
 
704
/** Call function with two parameters */
 
705
int cmd_call2(cmd_arg_t *argv)
 
706
{
 
707
        uintptr_t symaddr;
 
708
        char *symbol;
 
709
        unative_t (*fnc)(unative_t, unative_t, ...);
 
710
        unative_t arg1 = argv[1].intval;
 
711
        unative_t arg2 = argv[2].intval;
 
712
        fncptr_t fptr;
 
713
        int rc;
 
714
 
 
715
        symbol = (char *) argv->buffer;
 
716
        rc = symtab_addr_lookup(symbol, &symaddr);
 
717
 
 
718
        if (rc == ENOENT) {
 
719
                printf("Symbol %s not found.\n", symbol);
 
720
        } else if (rc == EOVERFLOW) {
 
721
                symtab_print_search(symbol);
 
722
                printf("Duplicate symbol, be more specific.\n");
 
723
        } else if (rc == EOK) {
 
724
                fnc = (unative_t (*)(unative_t, unative_t, ...)) arch_construct_function(&fptr, (void *) symaddr, (void *) cmd_call2);
 
725
                printf("Calling f(%#" PRIxn ", %#" PRIxn "): %p: %s\n", 
 
726
                       arg1, arg2, symaddr, symbol);
 
727
                printf("Result: %#" PRIxn "\n", fnc(arg1, arg2));
 
728
        } else {
 
729
                printf("No symbol information available.\n");
 
730
        }
 
731
        return 1;
 
732
}
 
733
 
 
734
/** Call function with three parameters */
 
735
int cmd_call3(cmd_arg_t *argv)
 
736
{
 
737
        uintptr_t symaddr;
 
738
        char *symbol;
 
739
        unative_t (*fnc)(unative_t, unative_t, unative_t, ...);
 
740
        unative_t arg1 = argv[1].intval;
 
741
        unative_t arg2 = argv[2].intval;
 
742
        unative_t arg3 = argv[3].intval;
 
743
        fncptr_t fptr;
 
744
        int rc;
 
745
        
 
746
        symbol = (char *) argv->buffer;
 
747
        rc = symtab_addr_lookup(symbol, &symaddr);
 
748
 
 
749
        if (rc == ENOENT) {
 
750
                printf("Symbol %s not found.\n", symbol);
 
751
        } else if (rc == EOVERFLOW) {
 
752
                symtab_print_search(symbol);
 
753
                printf("Duplicate symbol, be more specific.\n");
 
754
        } else if (rc == EOK) {
 
755
                fnc = (unative_t (*)(unative_t, unative_t, unative_t, ...)) arch_construct_function(&fptr, (void *) symaddr, (void *) cmd_call3);
 
756
                printf("Calling f(%#" PRIxn ",%#" PRIxn ", %#" PRIxn "): %p: %s\n", 
 
757
                       arg1, arg2, arg3, symaddr, symbol);
 
758
                printf("Result: %#" PRIxn "\n", fnc(arg1, arg2, arg3));
 
759
        } else {
 
760
                printf("No symbol information available.\n");
 
761
        }
 
762
        return 1;
 
763
}
 
764
 
 
765
 
 
766
/** Print detailed description of 'describe' command. */
 
767
void desc_help(void)
 
768
{
 
769
        printf("Syntax: describe command_name\n");
 
770
}
 
771
 
 
772
/** Halt the kernel.
 
773
 *
 
774
 * @param argv Argument vector (ignored).
 
775
 *
 
776
 * @return 0 on failure, 1 on success (never returns).
 
777
 */
 
778
int cmd_halt(cmd_arg_t *argv)
 
779
{
 
780
        halt();
 
781
        return 1;
 
782
}
 
783
 
 
784
/** Command for printing TLB contents.
 
785
 *
 
786
 * @param argv Not used.
 
787
 *
 
788
 * @return Always returns 1.
 
789
 */
 
790
int cmd_tlb(cmd_arg_t *argv)
 
791
{
 
792
        tlb_print();
 
793
        return 1;
 
794
}
 
795
 
 
796
/** Command for printing physical memory configuration.
 
797
 *
 
798
 * @param argv Not used.
 
799
 *
 
800
 * @return Always returns 1.
 
801
 */
 
802
int cmd_physmem(cmd_arg_t *argv)
 
803
{
 
804
        physmem_print();
 
805
        return 1;
 
806
}
 
807
 
 
808
/** Write 4 byte value to address */
 
809
int cmd_set4(cmd_arg_t *argv)
 
810
{
 
811
        uintptr_t addr;
 
812
        uint32_t arg1 = argv[1].intval;
 
813
        bool pointer = false;
 
814
        int rc;
 
815
 
 
816
        if (((char *)argv->buffer)[0] == '*') {
 
817
                rc = symtab_addr_lookup((char *) argv->buffer + 1, &addr);
 
818
                pointer = true;
 
819
        } else if (((char *) argv->buffer)[0] >= '0' && 
 
820
                   ((char *)argv->buffer)[0] <= '9') {
 
821
                rc = EOK;
 
822
                addr = atoi((char *)argv->buffer);
 
823
        } else {
 
824
                rc = symtab_addr_lookup((char *) argv->buffer, &addr);
 
825
        }
 
826
 
 
827
        if (rc == ENOENT)
 
828
                printf("Symbol %s not found.\n", argv->buffer);
 
829
        else if (rc == EOVERFLOW) {
 
830
                symtab_print_search((char *) argv->buffer);
 
831
                printf("Duplicate symbol, be more specific.\n");
 
832
        } else if (rc == EOK) {
 
833
                if (pointer)
 
834
                        addr = *(uintptr_t *) addr;
 
835
                printf("Writing %#" PRIx64 " -> %p\n", arg1, addr);
 
836
                *(uint32_t *) addr = arg1;
 
837
        } else {
 
838
                printf("No symbol information available.\n");
 
839
        }
 
840
        
 
841
        return 1;
 
842
}
 
843
 
 
844
/** Command for listings SLAB caches
 
845
 *
 
846
 * @param argv Ignores
 
847
 *
 
848
 * @return Always 1
 
849
 */
 
850
int cmd_slabs(cmd_arg_t * argv) {
 
851
        slab_print_list();
 
852
        return 1;
 
853
}
 
854
 
 
855
 
 
856
/** Command for listings Thread information
 
857
 *
 
858
 * @param argv Ignores
 
859
 *
 
860
 * @return Always 1
 
861
 */
 
862
int cmd_threads(cmd_arg_t * argv) {
 
863
        thread_print_list();
 
864
        return 1;
 
865
}
 
866
 
 
867
/** Command for listings Task information
 
868
 *
 
869
 * @param argv Ignores
 
870
 *
 
871
 * @return Always 1
 
872
 */
 
873
int cmd_tasks(cmd_arg_t * argv) {
 
874
        task_print_list();
 
875
        return 1;
 
876
}
 
877
 
 
878
/** Command for listings Thread information
 
879
 *
 
880
 * @param argv Ignores
 
881
 *
 
882
 * @return Always 1
 
883
 */
 
884
int cmd_sched(cmd_arg_t * argv) {
 
885
        sched_print_list();
 
886
        return 1;
 
887
}
 
888
 
 
889
/** Command for listing memory zones
 
890
 *
 
891
 * @param argv Ignored
 
892
 *
 
893
 * return Always 1
 
894
 */
 
895
int cmd_zones(cmd_arg_t * argv) {
 
896
        zone_print_list();
 
897
        return 1;
 
898
}
 
899
 
 
900
/** Command for memory zone details
 
901
 *
 
902
 * @param argv Integer argument from cmdline expected
 
903
 *
 
904
 * return Always 1
 
905
 */
 
906
int cmd_zone(cmd_arg_t * argv) {
 
907
        zone_print_one(argv[0].intval);
 
908
        return 1;
 
909
}
 
910
 
 
911
/** Command for printing task ipc details
 
912
 *
 
913
 * @param argv Integer argument from cmdline expected
 
914
 *
 
915
 * return Always 1
 
916
 */
 
917
int cmd_ipc(cmd_arg_t * argv) {
 
918
        ipc_print_task(argv[0].intval);
 
919
        return 1;
 
920
}
 
921
 
 
922
 
 
923
/** Command for listing processors.
 
924
 *
 
925
 * @param argv Ignored.
 
926
 *
 
927
 * return Always 1.
 
928
 */
 
929
int cmd_cpus(cmd_arg_t *argv)
 
930
{
 
931
        cpu_list();
 
932
        return 1;
 
933
}
 
934
 
 
935
/** Command for printing kernel version.
 
936
 *
 
937
 * @param argv Ignored.
 
938
 *
 
939
 * return Always 1.
 
940
 */
 
941
int cmd_version(cmd_arg_t *argv)
 
942
{
 
943
        version_print();
 
944
        return 1;
 
945
}
 
946
 
 
947
/** Command for returning console back to userspace.
 
948
 *
 
949
 * @param argv Ignored.
 
950
 *
 
951
 * return Always 1.
 
952
 */
 
953
int cmd_continue(cmd_arg_t *argv)
 
954
{
 
955
        printf("The kernel will now relinquish the console.\n");
 
956
        release_console();
 
957
        
 
958
        event_notify_0(EVENT_KCONSOLE);
 
959
        indev_pop_character(stdin);
 
960
        
 
961
        return 1;
 
962
}
 
963
 
 
964
#ifdef CONFIG_TEST
 
965
/** Command for printing kernel tests list.
 
966
 *
 
967
 * @param argv Ignored.
 
968
 *
 
969
 * return Always 1.
 
970
 */
 
971
int cmd_tests(cmd_arg_t *argv)
 
972
{
 
973
        size_t len = 0;
 
974
        test_t *test;
 
975
        for (test = tests; test->name != NULL; test++) {
 
976
                if (str_length(test->name) > len)
 
977
                        len = str_length(test->name);
 
978
        }
 
979
        
 
980
        for (test = tests; test->name != NULL; test++)
 
981
                printf("%-*s %s%s\n", len, test->name, test->desc, (test->safe ? "" : " (unsafe)"));
 
982
        
 
983
        printf("%-*s Run all safe tests\n", len, "*");
 
984
        return 1;
 
985
}
 
986
 
 
987
static bool run_test(const test_t *test)
 
988
{
 
989
        printf("%s (%s)\n", test->name, test->desc);
 
990
        
 
991
        /* Update and read thread accounting
 
992
           for benchmarking */
 
993
        ipl_t ipl = interrupts_disable();
 
994
        spinlock_lock(&TASK->lock);
 
995
        uint64_t t0 = task_get_accounting(TASK);
 
996
        spinlock_unlock(&TASK->lock);
 
997
        interrupts_restore(ipl);
 
998
        
 
999
        /* Execute the test */
 
1000
        test_quiet = false;
 
1001
        char *ret = test->entry();
 
1002
        
 
1003
        /* Update and read thread accounting */
 
1004
        ipl = interrupts_disable();
 
1005
        spinlock_lock(&TASK->lock);
 
1006
        uint64_t dt = task_get_accounting(TASK) - t0;
 
1007
        spinlock_unlock(&TASK->lock);
 
1008
        interrupts_restore(ipl);
 
1009
        
 
1010
        uint64_t cycles;
 
1011
        char suffix;
 
1012
        order(dt, &cycles, &suffix);
 
1013
                
 
1014
        printf("Time: %" PRIu64 "%c cycles\n", cycles, suffix);
 
1015
        
 
1016
        if (ret == NULL) {
 
1017
                printf("Test passed\n");
 
1018
                return true;
 
1019
        }
 
1020
 
 
1021
        printf("%s\n", ret);
 
1022
        return false;
 
1023
}
 
1024
 
 
1025
static bool run_bench(const test_t *test, const uint32_t cnt)
 
1026
{
 
1027
        uint32_t i;
 
1028
        bool ret = true;
 
1029
        uint64_t cycles;
 
1030
        char suffix;
 
1031
        
 
1032
        if (cnt < 1)
 
1033
                return true;
 
1034
        
 
1035
        uint64_t *data = (uint64_t *) malloc(sizeof(uint64_t) * cnt, 0);
 
1036
        if (data == NULL) {
 
1037
                printf("Error allocating memory for statistics\n");
 
1038
                return false;
 
1039
        }
 
1040
        
 
1041
        for (i = 0; i < cnt; i++) {
 
1042
                printf("%s (%u/%u) ... ", test->name, i + 1, cnt);
 
1043
                
 
1044
                /* Update and read thread accounting
 
1045
                   for benchmarking */
 
1046
                ipl_t ipl = interrupts_disable();
 
1047
                spinlock_lock(&TASK->lock);
 
1048
                uint64_t t0 = task_get_accounting(TASK);
 
1049
                spinlock_unlock(&TASK->lock);
 
1050
                interrupts_restore(ipl);
 
1051
                
 
1052
                /* Execute the test */
 
1053
                test_quiet = true;
 
1054
                char * ret = test->entry();
 
1055
                
 
1056
                /* Update and read thread accounting */
 
1057
                ipl = interrupts_disable();
 
1058
                spinlock_lock(&TASK->lock);
 
1059
                uint64_t dt = task_get_accounting(TASK) - t0;
 
1060
                spinlock_unlock(&TASK->lock);
 
1061
                interrupts_restore(ipl);
 
1062
                
 
1063
                if (ret != NULL) {
 
1064
                        printf("%s\n", ret);
 
1065
                        ret = false;
 
1066
                        break;
 
1067
                }
 
1068
                
 
1069
                data[i] = dt;
 
1070
                order(dt, &cycles, &suffix);
 
1071
                printf("OK (%" PRIu64 "%c cycles)\n", cycles, suffix);
 
1072
        }
 
1073
        
 
1074
        if (ret) {
 
1075
                printf("\n");
 
1076
                
 
1077
                uint64_t sum = 0;
 
1078
                
 
1079
                for (i = 0; i < cnt; i++) {
 
1080
                        sum += data[i];
 
1081
                }
 
1082
                
 
1083
                order(sum / (uint64_t) cnt, &cycles, &suffix);
 
1084
                printf("Average\t\t%" PRIu64 "%c\n", cycles, suffix);
 
1085
        }
 
1086
        
 
1087
        free(data);
 
1088
        
 
1089
        return ret;
 
1090
}
 
1091
 
 
1092
/** Command for returning kernel tests
 
1093
 *
 
1094
 * @param argv Argument vector.
 
1095
 *
 
1096
 * return Always 1.
 
1097
 */
 
1098
int cmd_test(cmd_arg_t *argv)
 
1099
{
 
1100
        test_t *test;
 
1101
        
 
1102
        if (str_cmp((char *) argv->buffer, "*") == 0) {
 
1103
                for (test = tests; test->name != NULL; test++) {
 
1104
                        if (test->safe) {
 
1105
                                printf("\n");
 
1106
                                if (!run_test(test))
 
1107
                                        break;
 
1108
                        }
 
1109
                }
 
1110
        } else {
 
1111
                bool fnd = false;
 
1112
                
 
1113
                for (test = tests; test->name != NULL; test++) {
 
1114
                        if (str_cmp(test->name, (char *) argv->buffer) == 0) {
 
1115
                                fnd = true;
 
1116
                                run_test(test);
 
1117
                                break;
 
1118
                        }
 
1119
                }
 
1120
                
 
1121
                if (!fnd)
 
1122
                        printf("Unknown test\n");
 
1123
        }
 
1124
        
 
1125
        return 1;
 
1126
}
 
1127
 
 
1128
/** Command for returning kernel tests as benchmarks
 
1129
 *
 
1130
 * @param argv Argument vector.
 
1131
 *
 
1132
 * return Always 1.
 
1133
 */
 
1134
int cmd_bench(cmd_arg_t *argv)
 
1135
{
 
1136
        test_t *test;
 
1137
        uint32_t cnt = argv[1].intval;
 
1138
        
 
1139
        if (str_cmp((char *) argv->buffer, "*") == 0) {
 
1140
                for (test = tests; test->name != NULL; test++) {
 
1141
                        if (test->safe) {
 
1142
                                if (!run_bench(test, cnt))
 
1143
                                        break;
 
1144
                        }
 
1145
                }
 
1146
        } else {
 
1147
                bool fnd = false;
 
1148
                
 
1149
                for (test = tests; test->name != NULL; test++) {
 
1150
                        if (str_cmp(test->name, (char *) argv->buffer) == 0) {
 
1151
                                fnd = true;
 
1152
                                
 
1153
                                if (test->safe)
 
1154
                                        run_bench(test, cnt);
 
1155
                                else
 
1156
                                        printf("Unsafe test\n");
 
1157
                                
 
1158
                                break;
 
1159
                        }
 
1160
                }
 
1161
                
 
1162
                if (!fnd)
 
1163
                        printf("Unknown test\n");
 
1164
        }
 
1165
        
 
1166
        return 1;
 
1167
}
 
1168
 
 
1169
#endif
 
1170
 
 
1171
/** @}
 
1172
 */