root/sys/arch/bebox/stand/boot/monitor.c
/*      $NetBSD: monitor.c,v 1.11 2016/06/11 06:28:49 dholland Exp $    */

/*-
 * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Kazuki Sakamoto.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <lib/libsa/stand.h>
#include <lib/libkern/libkern.h>

#include "boot.h"

extern int errno;
extern char *name;

void db_cmd_dump(int, char **);
void db_cmd_get(int, char **);
void db_cmd_mf(int, char **);
void db_cmd_mt(int, char **);
void db_cmd_put(int, char **);
void db_cmd_help(int, char **);

uint32_t db_atob(char *);

struct {
        char *name;
        void (*fcn)(int, char **);
} db_cmd[] = {
        { "dump",       db_cmd_dump },
        { "get",        db_cmd_get },
        { "mf",         db_cmd_mf },
        { "mt",         db_cmd_mt },
        { "put",        db_cmd_put },
        { "help",       db_cmd_help },
        { NULL,         NULL },
};

int
db_monitor(void)
{
        int tmp;
        int argc, flag;
        char *p, *argv[16];
        char line[1024];

        while (1) {
                printf("db> ");
                kgets(line, sizeof(line));

                flag = 0;
                for (p = line, argc = 0; *p != '\0'; p++) {
                        if (*p != ' ' && *p != '\t') {
                                if (!flag) {
                                        flag++;
                                        argv[argc++] = p;
                                }
                        } else {
                                if (flag) {
                                        *p = '\0';
                                        flag = 0;
                                }
                        }
                }

                if (argc == 0)
                        continue;

                tmp = 0;
                while (db_cmd[tmp].name != NULL) {
                        if (!strcmp("continue", argv[0]))
                                return 0;
                        if (!strcmp(db_cmd[tmp].name, argv[0])) {
                                (db_cmd[tmp].fcn)(argc, argv);
                                break;
                        }
                        tmp++;
                }
                if (db_cmd[tmp].name == NULL)
                        db_cmd_help(argc, argv);
        }
        return 0;
}

uint32_t
db_atob(char *p)
{
        uint32_t b = 0;
        int width, tmp, exp, x = 0;

        if (p[1] == 'x') {
                p += 2;
                x = 1;
        }
        width = strlen(p);
        while (width--) {
                exp = 1;
                for (tmp = 1; tmp <= width; tmp++)
                        exp *= (x ? 16 : 10);
                if (*p >= '0' && *p <= '9') {
                        tmp = *p - '0';
                } else {
                        tmp = *p - 'a' + 10;
                }
                b += tmp * exp;
                p++;
        }
        return b;
}

void
db_cmd_dump(int argc, char **argv)
{
        char *p, *r, *pp;
        int mode, size, i;
        uint32_t add;

        switch (argc) {
        case 4:
                r = argv[1];
                switch (r[1]) {
                case 'b':
                        mode = 1;
                        break;
                case 'h':
                        mode = 2;
                        break;
                case 'w':
                        mode = 4;
                        break;
                default:
                        goto out;
                }
                p = argv[2];
                pp = argv[3];
                break;
        case 3:
                mode = 4;
                p = argv[1];
                pp = argv[2];
                break;
        default:
                goto out;
        }

        add = db_atob(p);
        size = db_atob(pp);
        i = 0;
        for (; size > 0;) {
                if (!i)
                        printf("\n0x%x:", add);
                switch (mode) {
                case 1:
                        printf(" %x", *(uint8_t *)add);
                        add += 1;
                        size -= 1;
                        if (++i == 16)
                                i = 0;
                        break;
                case 2:
                        printf(" %x", *(uint16_t *)add);
                        add += 2;
                        size -= 2;
                        if (++i == 8)
                                i = 0;
                        break;
                case 4:
                        printf(" %x", *(uint32_t *)add);
                        add += 4;
                        size -= 4;
                        if (++i == 4)
                                i = 0;
                        break;
                }
        }
        printf("\n");
        return;

out:
        printf("dump [-b][-h][-w] address size\n");
        return;
}

void
db_cmd_get(int argc, char **argv)
{
        char *p, *r;
        uint32_t add;
        int mode;

        switch (argc) {
        case 3:
                r = argv[1];
                switch (r[1]) {
                case 'b':
                        mode = 1;
                        break;
                case 'h':
                        mode = 2;
                        break;
                case 'w':
                        mode = 4;
                        break;
                default:
                        goto out;
                }
                p = argv[2];
                break;
        case 2:
                mode = 4;
                p = argv[1];
                break;
        default:
                goto out;
        }

        add = db_atob(p);
        printf("0x%x: ", add);
        switch (mode) {
        case 1:
                printf("0x%x", *(uint8_t *)add);
                break;
        case 2:
                printf("0x%x", *(uint16_t *)add);
                break;
        case 4:
                printf("0x%x", *(uint32_t *)add);
                break;
        }
        printf("\n");
        return;

out:
        printf("get [-b][-h][-w] address\n");
        return;
}

void
db_cmd_put(int argc, char **argv)
{
        char *p, *r, *pp;
        uint32_t add, data;
        int mode;

        switch (argc) {
        case 4:
                r = argv[1];
                switch (r[1]) {
                case 'b':
                        mode = 1;
                        break;
                case 'h':
                        mode = 2;
                        break;
                case 'w':
                        mode = 4;
                        break;
                default:
                        goto out;
                }
                p = argv[2];
                pp = argv[3];
                break;
        case 3:
                mode = 4;
                p = argv[1];
                pp = argv[2];
                break;
        default:
                goto out;
        }

        add = db_atob(p);
        data = db_atob(pp);
        printf("0x%x: 0x%x", add, data);
        switch (mode) {
        case 1:
                *(uint8_t *)add = data;
                break;
        case 2:
                *(uint16_t *)add = data;
                break;
        case 4:
                *(uint32_t *)add = data;
                break;
        }
        printf("\n");
        return;

out:
        printf("put [-b][-h][-w] address data\n");
        return;
}

#define STR(x) #x

#define FUNC(x) \
uint32_t mf ## x(void); \
void mt ## x(uint32_t); \
uint32_t mf ## x() { \
        uint32_t tmp; \
        __asm volatile (STR(mf ## x %0) : STR(=r)(tmp)); \
        return (tmp); \
} \
void mt ## x(uint32_t data) \
{ \
        __asm volatile (STR(mt ## x %0) :: STR(r)(data)); \
} \

#define DEF(x) \
        { #x, mf ## x, mt ## x }

FUNC(msr)

struct {
        char *op;
        uint32_t (*mf)(void);
        void (*mt)(uint32_t);
} mreg [] = {
        DEF(msr),
        { NULL, NULL, NULL },
};

void
db_cmd_mf(int argc, char **argv)
{
        int i = 0;

        if (argc != 2) {
                printf("mf register\nregister:");
                while (mreg[i].op != NULL)
                        printf(" %s", mreg[i++].op);
                printf("\n");
                return;
        }

        while (mreg[i].op != NULL) {
                if (!strcmp(mreg[i].op, argv[1])) {
                        printf(" 0x%x\n", (mreg[i].mf)());
                        break;
                }
                i++;
        }
}

void
db_cmd_mt(int argc, char **argv)
{
        int i = 0;

        if (argc != 3) {
                printf("mt register data\nregister:");
                while (mreg[i].op != NULL)
                        printf(" %s", mreg[i++].op);
                printf("\n");
                return;
        }

        while (mreg[i].op != NULL) {
                if (!strcmp(mreg[i].op, argv[1])) {
                        (mreg[i].mt)(db_atob(argv[2]));
                        printf(" 0x%x\n", db_atob(argv[2]));
                        break;
                }
                i++;
        }
}

void
db_cmd_help(int argc, char **argv)
{
        int i = 0;

        while (db_cmd[i].name != NULL)
                printf("%s, ", db_cmd[i++].name);
        printf("\n");
}