Subversion Repositories HelenOS

Rev

Rev 4011 | Rev 4132 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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