#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: main.c,v 1.8 2026/06/11 19:46:18 andvar Exp $");
#include <lib/libsa/stand.h>
#include <lib/libsa/loadfile.h>
#include <lib/libkern/libkern.h>
#include <hpcmips/vr/vripreg.h>
#include <hpcmips/vr/cmureg.h>
#include <hpcmips/vr/vr4181giureg.h>
#include "extern.h"
#include "i28f128reg.h"
#define ISABRGCTL 0x00
#define ISABRGSTS 0x02
#define XISACTL 0x04
#define BOOTTIMEOUT 9
#define LINEBUFLEN 80
extern const char bootprog_rev[];
extern const char bootprog_name[];
static void command_help(char *opt);
static void command_dump(char *opt);
static void command_boot(char *opt);
static void command_load(char *opt);
static void command_fill(char *opt);
static void command_write(char *opt);
static void command_option(char *subcmd);
static void opt_subcmd_print(char *opt);
static void opt_subcmd_read(char *opt);
static void opt_subcmd_write(char *opt);
static void opt_subcmd_path(char *opt);
static void opt_subcmd_bootp(char *opt);
static void opt_subcmd_ip(char *opt);
struct boot_option bootopts;
static struct bootmenu_command commands[] = {
{ "?", command_help },
{ "h", command_help },
{ "d", command_dump },
{ "b", command_boot },
{ "l", command_load },
{ "f", command_fill },
{ "w", command_write },
{ "o", command_option },
{ NULL, NULL },
};
static struct bootmenu_command opt_subcommands[] = {
{ "p", opt_subcmd_print },
{ "r", opt_subcmd_read },
{ "w", opt_subcmd_write },
{ "path", opt_subcmd_path },
{ "bootp", opt_subcmd_bootp },
{ "ip", opt_subcmd_ip },
{ NULL, NULL },
};
static void
print_banner(void)
{
printf("\n");
printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev);
#if 0
printf(">> Memory: %d/%d k\n", getbasemem(), getextmem());
#endif
}
static void
init_devices(void)
{
REGWRITE_2(VRETIMEH, 0, 0);
REGWRITE_2(VRETIMEM, 0, 0);
REGWRITE_2(VRETIMEL, 0, 0);
REGWRITE_2(VR4181_ISABRG_ADDR, ISABRGCTL, 0x0003);
REGWRITE_2(VR4181_ISABRG_ADDR, XISACTL, 0x0401);
REGWRITE_2(VR4181_CMU_ADDR, 0, CMUMASK_SIU | CMUMASK_AIU);
#if 0
REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_PIOD_L_REG_W, 0xffff);
REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE0_REG_W,
GP3_PCS0 | GP2_GPO);
REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE1_REG_W, GP8_GPO);
REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE2_REG_W,
GP23_ROMCS1 | GP22_ROMCS0 | GP21_RESET
| GP18_IORDY | GP17_IOWR | GP16_IORD);
REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE3_REG_W,
GP30_GPI
| GP28_CTS1 | GP27_RTS1 | GP26_TxD1 | GP25_RxD1
| GP24_ROMCS2);
#else
REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_PIOD_L_REG_W, 0xffff);
REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE0_REG_W,
GP6_GPO | GP5_GPO | GP3_PCS0
| GP2_GPO | GP1_GPO | GP0_GPO);
REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE1_REG_W,
GP12_GPI | GP8_GPO);
REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE2_REG_W,
GP23_ROMCS1 | GP22_ROMCS0 | GP21_RESET
| GP18_IORDY | GP17_IOWR | GP16_IORD);
REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE3_REG_W,
GP30_GPI
| GP28_CTS1 | GP27_RTS1 | GP26_TxD1 | GP25_RxD1
| GP24_ROMCS2);
#endif
#if 0
REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_INTTYP_L_REG_W,
I4TYP_HIGH_LEVEL);
REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_INTMASK_REG_W,
0xffffU & ~GIMSK4);
REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_INTEN_REG_W, GIEN4);
#endif
REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_PCS0STRA_REG_W, 0x0000);
REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_PCS0STPA_REG_W, 0x0fff);
REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_PCS0HIA_REG_W, 0x1401);
REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_PCSMODE_REG_W,
PCS0MIOB_IO | PCS0DSIZE_16BIT | PCS0MD_READWRITE);
}
static char *
get_next_arg(char *arg)
{
char *opt;
if ((opt = strchr(arg, ' ')) == NULL) {
opt = "";
} else {
*opt++ = '\0';
}
while (*opt == ' ')
opt++;
return opt;
}
static void
command_help(char *opt)
{
printf("commands are:\n"
"boot:\tb\n"
"dump:\td addr [addr]\n"
"fill:\tf addr addr char\n"
"load:\tl [offset] (with following S-Record)\n"
"write:\tw dst src len\n"
"option:\to subcommand [params]\n"
"help:\th|?\n"
"\n"
"option subcommands are:\n"
"print:\to p\n"
"read:\to r\n"
"write:\to w\n"
"path:\to path pathname\n"
"bootp:\to bootp yes|no\n"
"ip:\to ip remote local netmask gateway\n"
);
}
static void
bad_param(void)
{
printf("bad param\n");
command_help(NULL);
}
static const u_int8_t print_cnv[] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
static void
printhexul(u_int32_t n)
{
int i;
for (i = 28; i >= 0; i -= 4)
putchar(print_cnv[(n >> i) & 0x0f]);
}
static void
printhexuc(u_int8_t n)
{
int i;
for (i = 4; i >= 0; i -= 4)
putchar(print_cnv[(n >> i) & 0x0f]);
}
static void
command_dump(char *opt)
{
char *endptr;
const char *p;
const char *line_fence;
const char *limit;
p = (const char *) strtoul(opt, &endptr, 16);
if (opt == endptr) {
bad_param();
return;
}
opt = get_next_arg(opt);
limit = (const char *) strtoul(opt, &endptr, 16);
if (opt == endptr) {
limit = p + 256;
}
for (;;) {
printhexul((u_int32_t) p);
putchar(' ');
line_fence = p + 16;
while (p < line_fence) {
printhexuc(*p++);
putchar(' ');
if (p >= limit) {
putchar('\n');
return;
}
}
putchar('\n');
if (ISKEY) {
if (getchar() == '\x03')
break;
}
}
}
static void
command_boot(char *opt)
{
u_long marks[MARK_MAX];
marks[MARK_START] = 0;
if (loadfile(bootopts.b_pathname, marks, LOAD_KERNEL)) {
printf("loadfile failed\n");
return;
}
start_netbsd();
}
static int
load_srec(char *offset)
{
char s2lbuf[9];
char c;
char rectype;
u_int32_t reclen;
u_int32_t reclen_bk;
u_int32_t recaddr;
char *endptr;
char *p;
u_int32_t sum;
int err = 0;
for (;;) {
if ((c = getchar()) != 'S')
goto out;
rectype = getchar();
s2lbuf[0] = getchar();
s2lbuf[1] = getchar();
s2lbuf[2] = '\0';
reclen_bk = reclen = strtoul(s2lbuf, &endptr, 16);
if (endptr != &s2lbuf[2])
goto out;
sum = reclen;
p = s2lbuf;
switch (rectype) {
case '0':
do {
c = getchar();
} while (c != '\r' && c != '\n');
continue;
case '3':
*p++ = getchar();
*p++ = getchar();
reclen--;
case '2':
*p++ = getchar();
*p++ = getchar();
reclen--;
case '1':
*p++ = getchar();
*p++ = getchar();
*p++ = getchar();
*p++ = getchar();
*p = '\0';
reclen -= 2;
recaddr = strtoul(s2lbuf, &endptr, 16);
if (endptr != p)
goto out;
sum += (recaddr >> 24) & 0xff;
sum += (recaddr >> 16) & 0xff;
sum += (recaddr >> 8) & 0xff;
sum += recaddr & 0xff;
p = offset + recaddr;
reclen--;
s2lbuf[2] = '\0';
while (reclen > 0) {
s2lbuf[0] = getchar();
s2lbuf[1] = getchar();
*p = (u_int8_t) strtoul(s2lbuf, &endptr, 16);
if (endptr != &s2lbuf[2])
goto out;
sum += *p++;
reclen--;
}
break;
case '7':
case '8':
case '9':
goto out2;
default:
goto out;
}
s2lbuf[0] = getchar();
s2lbuf[1] = getchar();
s2lbuf[2] = '\0';
sum += (strtoul(s2lbuf, &endptr, 16) & 0xff);
sum &= 0xff;
if (sum != 0xff) {
printf("checksum error\n");
err = 1;
goto out2;
}
c = getchar();
if (c != '\r' && c != '\n')
goto out;
}
return 1;
out:
printf("invalid S-Record\n");
err = 1;
out2:
do {
c = getchar();
} while (c != '\r' && c != '\n');
return err;
}
static void
command_load(char *opt)
{
char *endptr;
char *offset;
offset = (char *) strtoul(opt, &endptr, 16);
if (opt == endptr)
offset = 0;
load_srec(offset);
}
static void
command_fill(char *opt)
{
char *endptr;
char *p;
char *limit;
int c;
p = (char *) strtoul(opt, &endptr, 16);
if (opt == endptr) {
bad_param();
return;
}
opt = get_next_arg(opt);
limit = (char *) strtoul(opt, &endptr, 16);
if (opt == endptr) {
bad_param();
return;
}
opt = get_next_arg(opt);
c = strtoul(opt, &endptr, 16);
if (opt == endptr)
c = '\0';
memset(p, c, limit - p);
}
static void
check_write_verify_flash(u_int32_t src, u_int32_t dst, size_t len)
{
int status;
if ((dst & I28F128_BLOCK_MASK) != 0) {
printf("dst addr must be aligned to block boundary (0x%x)\n",
I28F128_BLOCK_SIZE);
return;
}
if (i28f128_probe((void *) dst)) {
printf("dst addr is not a intel 28F128\n");
} else {
printf("intel 28F128 detected\n");
}
if ((status = i28f128_region_write((void *) dst, (void *) src, len))
!= 0) {
printf("write mem to flash failed status = %x\n", status);
return;
}
printf("verifying...");
if (memcmp((void *) dst, (void *) src, len)) {
printf("verify error\n");
return;
}
printf("ok\n");
printf("writing memory to flash succeeded\n");
}
static void
command_write(char *opt)
{
char *endptr;
u_int32_t src;
u_int32_t dst;
size_t len;
dst = strtoul(opt, &endptr, 16);
if (opt == endptr)
goto out;
opt = get_next_arg(opt);
src = strtoul(opt, &endptr, 16);
if (opt == endptr)
goto out;
opt = get_next_arg(opt);
len = strtoul(opt, &endptr, 16);
if (opt == endptr)
goto out;
check_write_verify_flash(src, dst, len);
return;
out:
bad_param();
return;
}
static void
command_option(char *subcmd)
{
char *opt;
int i;
opt = get_next_arg(subcmd);
for (i = 0; opt_subcommands[i].c_name != NULL; i++) {
if (strcmp(subcmd, opt_subcommands[i].c_name) == 0) {
opt_subcommands[i].c_fn(opt);
break;
}
}
if (opt_subcommands[i].c_name == NULL) {
printf("unknown option subcommand\n");
command_help(NULL);
}
}
static void
opt_subcmd_print(char *opt)
{
printf("boot options:\n"
"magic:\t\t%s\n"
"pathname:\t`%s'\n"
"bootp:\t\t%s\n",
bootopts.b_magic == BOOTOPT_MAGIC ? "ok" : "bad",
bootopts.b_pathname,
bootopts.b_flags & B_F_USE_BOOTP ? "yes" : "no");
printf("remote IP:\t%s\n", inet_ntoa(bootopts.b_remote_ip));
printf("local IP:\t%s\n", inet_ntoa(bootopts.b_local_ip));
printf("netmask:\t%s\n", intoa(bootopts.b_netmask));
printf("gateway IP:\t%s\n", inet_ntoa(bootopts.b_gate_ip));
}
static void
opt_subcmd_read(char *opt)
{
bootopts = *((struct boot_option *) BOOTOPTS_BASE);
if (bootopts.b_magic != BOOTOPT_MAGIC)
bootopts.b_pathname[0] = '\0';
}
static void
opt_subcmd_write(char *opt)
{
bootopts.b_magic = BOOTOPT_MAGIC;
check_write_verify_flash((u_int32_t) &bootopts, BOOTOPTS_BASE,
sizeof bootopts);
}
static void
opt_subcmd_path(char *opt)
{
strlcpy(bootopts.b_pathname, opt, sizeof bootopts.b_pathname);
}
static void
opt_subcmd_bootp(char *opt)
{
if (strcmp(opt, "yes") == 0) {
bootopts.b_flags |= B_F_USE_BOOTP;
} else if (strcmp(opt, "no") == 0) {
bootopts.b_flags &= ~B_F_USE_BOOTP;
} else {
bad_param();
}
}
static void
opt_subcmd_ip(char *opt)
{
bootopts.b_remote_ip.s_addr = inet_addr(opt);
opt = get_next_arg(opt);
bootopts.b_local_ip.s_addr = inet_addr(opt);
opt = get_next_arg(opt);
bootopts.b_netmask = inet_addr(opt);
opt = get_next_arg(opt);
bootopts.b_gate_ip.s_addr = inet_addr(opt);
}
static void
bootmenu(void)
{
char input[LINEBUFLEN];
char *cmd;
char *opt;
int i;
for (;;) {
input[0] = '\0';
printf("> ");
kgets(input, sizeof(input));
cmd = input;
while(*cmd == ' ')
cmd++;
if(*cmd) {
opt = get_next_arg(cmd);
for (i = 0; commands[i].c_name != NULL; i++) {
if (strcmp(cmd, commands[i].c_name) == 0) {
commands[i].c_fn(opt);
break;
}
}
if (commands[i].c_name == NULL) {
printf("unknown command\n");
command_help(NULL);
}
}
}
}
static char
awaitkey(void)
{
int i;
int j;
char c = 0;
while (ISKEY)
getchar();
for (i = BOOTTIMEOUT; i > 0; i--) {
printf("%d\b", i);
for (j = 0; j < 1000000; j++) {
if (ISKEY) {
while (ISKEY)
c = getchar();
goto out;
}
}
}
out:
printf("0\n");
return(c);
}
__dead void
_rtt(void)
{
for (;;)
;
}
int
main(void)
{
char c;
init_devices();
comcninit();
opt_subcmd_read(NULL);
print_banner();
c = awaitkey();
if (c != '\r' && c != '\n' && c != '\0') {
printf("type \"?\" or \"h\" for help.\n");
bootmenu();
}
command_boot(NULL);
bootmenu();
return 0;
}