/* $NetBSD: main.c,v 1.7 2016/06/11 06:29:24 dholland Exp $ */ /* * Copyright (c) 2003 Naoto Shimazaki. * All rights reserved. * * 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 NAOTO SHIMAZAKI 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 NAOTO 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. */ /* * Boot loader for L-Card+ * * ROM Map * ------- * ROM1 * BFFF FFFF ------------------------------ * * reserved * * BF80 0000 ------------------------------ * * ROM0 * BFFF FFFF ------------------------------ * * user storage (max 2Mbytes) * * BFE0 0000 ------------------------------ * * reserved * * BFD4 0000 ------------------------------ * * boot params * * BFD2 0000 ------------------------------ * * second boot loader (mirror image) * or Linux Kernel * * BFD0 0000 ------------------------------ * * first boot loader (L-Card+ original loader) * * reset vector * BFC0 0000 ------------------------------ * * gziped kernel image (max 4Mbytes) * * BF80 0000 ------------------------------ * * * * RAM Map * ------- * * 80FF FFFF ------------------------------ * ROM ICE work * 80FF FE00 ------------------------------ * ROM ICE stack * 80FF FDA8 ------------------------------ * * * * kernel * 8004 0000 ------------------------------ * kernel stack (growing to lower) * * * boot loader heap (growing to upper) * boot loader text & data (at exec time) * 8000 1000 ------------------------------ * vector table * 8000 0000 ------------------------------ * * virtual memory space * * 0000 0000 ------------------------------ * * * * ROMCS0 <-> ROMCS3 mapping * * ROMCS0 ROMCS3 * BE7F FFFF <-> BFFF FFFF * BE40 0000 <-> BFC0 0000 reset vector * BE00 0000 <-> BF80 0000 * * */ #include __KERNEL_RCSID(0, "$NetBSD: main.c,v 1.7 2016/06/11 06:29:24 dholland Exp $"); #include #include #include #include #include #include #include "extern.h" #include "i28f128reg.h" /* XXX */ #define ISABRGCTL 0x00 #define ISABRGSTS 0x02 #define XISACTL 0x04 #define BOOTTIMEOUT 9 /* must less than 10 */ #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) { /* Init RTC */ REGWRITE_2(VRETIMEH, 0, 0); REGWRITE_2(VRETIMEM, 0, 0); REGWRITE_2(VRETIMEL, 0, 0); /* * CLKSPEEDREG 0x6012 * DIV DIV2 mode * CLKSP 18 (0x12) * PClock (CPU clock) 65.536MHz * PClock = (18.432MHz / CLKSP) x 64 * = (18.432MHz / 18) x 64 * = 65.536MHz * TClock (peripheral clock) 32.768MHz * TClock = PClock / DIV * = 65.536MHz / 2 * = 32.768MHz */ /* * setup ISA BUS clock freqency * * set PCLK (internal peripheral clock) to 32.768MHz (TClock / 1) * set External ISA bus clock to 10.922MHz (TClock / 3) */ REGWRITE_2(VR4181_ISABRG_ADDR, ISABRGCTL, 0x0003); REGWRITE_2(VR4181_ISABRG_ADDR, XISACTL, 0x0401); /* * setup peripheral's clock supply * * CSU: disable * AIU: enable (AIU, ADU, ADU18M) * PIU: disable * SIU: enable (SIU18M) */ REGWRITE_2(VR4181_CMU_ADDR, 0, CMUMASK_SIU | CMUMASK_AIU); /* * setup GPIO */ #if 0 /* L-Card+ generic setup */ /* * pin mode comment * GP0 : GPI not used * GP1 : GPI not used * GP2 : GPO LED6 (0: on 1: off) * GP3 : PCS0 chip select for CS8900A Lan controller * GP4 : GPI IRQ input from CS8900A * GP5 : GPI not used * GP6 : GPI not used * GP7 : GPI reserved by TANBAC TB0193 */ REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_PIOD_L_REG_W, 0xffff); REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE0_REG_W, GP3_PCS0 | GP2_GPO); /* * pin mode comment * GP8 : GPO LED5 (0: on 1: off) * GP9 : GPI CD2 * GP10: GPI CD1 * GP11: GPI not used * GP12: GPI not used * GP13: GPI not used * GP14: GPI not used * GP15: GPI not used */ REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE1_REG_W, GP8_GPO); /* * pin mode comment * GP16: IORD ISA bus * GP17: IOWR ISA bus * GP18: IORDY ISA bus * GP19: GPI not used * GP20: GPI not used * GP21: RESET resets CS8900A * GP22: ROMCS0 ROM chip select * GP23: ROMCS1 ROM chip select */ REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE2_REG_W, GP23_ROMCS1 | GP22_ROMCS0 | GP21_RESET | GP18_IORDY | GP17_IOWR | GP16_IORD); /* * GP24: ROMCS2 ROM chip select * GP25: RxD1 SIU1 * GP26: TxD1 SIU1 * GP27: RTS1 SIU1 * GP28: CTS1 SIU1 * GP29: GPI LED3 * GP30: GPI reserved by TANBAC TB0193 * GP31: GPI LED4 */ REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE3_REG_W, GP30_GPI | GP28_CTS1 | GP27_RTS1 | GP26_TxD1 | GP25_RxD1 | GP24_ROMCS2); #else /* e-care node specific setup */ /* * pin mode comment * GP0 : GPO ECNRTC_RST * GP1 : GPO ECNRTC_CLK * GP2 : GPO LED6 (0: on 1: off) * GP3 : PCS0 chip select for CS8900A Lan controller * GP4 : GPI IRQ input from CS8900A * GP5 : GPO ECNRTC_DIR * GP6 : GPO ECNRTC_OUT * GP7 : GPI reserved by TANBAC TB0193 */ 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); /* * pin mode comment * GP8 : GPO LED5 (0: on 1: off) * GP9 : GPI CD2 * GP10: GPI CD1 * GP11: GPI not used * GP12: GPI ECNRTC_IN * GP13: GPI not used * GP14: GPI not used * GP15: GPI not used */ REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE1_REG_W, GP12_GPI | GP8_GPO); /* * pin mode comment * GP16: IORD ISA bus * GP17: IOWR ISA bus * GP18: IORDY ISA bus * GP19: GPI not used * GP20: GPI not used * GP21: RESET resets CS8900A * GP22: ROMCS0 ROM chip select * GP23: ROMCS1 ROM chip select */ REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE2_REG_W, GP23_ROMCS1 | GP22_ROMCS0 | GP21_RESET | GP18_IORDY | GP17_IOWR | GP16_IORD); /* * GP24: ROMCS2 ROM chip select * GP25: RxD1 SIU1 * GP26: TxD1 SIU1 * GP27: RTS1 SIU1 * GP28: CTS1 SIU1 * GP29: GPI LED3 * GP30: GPI reserved by TANBAC TB0193 * GP31: GPI LED4 */ REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE3_REG_W, GP30_GPI | GP28_CTS1 | GP27_RTS1 | GP26_TxD1 | GP25_RxD1 | GP24_ROMCS2); #endif #if 0 /* * setup interrupt * * I4TYP: falling edge trigger * GIMSK4: unmask * GIEN4: enable * other: unused, mask, disable */ 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 /* * programmable chip select * * PCS0 is used to select CS8900A Ethernet controller * on TB0193 * * PCS0: * 0x14010000 - 0x14010fff * I/O access, 16bit cycle, both of read/write * PCS1: unused */ 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); } /* * chops the head from the arguments and returns the arguments if any, * or possibly an empty string. */ static char * get_next_arg(char *arg) { char *opt; if ((opt = strchr(arg, ' ')) == NULL) { opt = ""; } else { *opt++ = '\0'; } /* trim leading blanks */ 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(); /* no return */ } /* * loading S-Record */ 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 (;;) { /* * the first step is to read a S-Record. */ 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': /* just ignore */ do { c = getchar(); } while (c != '\r' && c != '\n'); continue; case '3': *p++ = getchar(); *p++ = getchar(); reclen--; /* FALLTHRU */ case '2': *p++ = getchar(); *p++ = getchar(); reclen--; /* FALLTHRU */ 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; /* * XXX * address range is must be chaked here! */ 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; } /* never reach */ 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); /* dispatch subcommand */ 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 a line */ input[0] = '\0'; printf("> "); kgets(input, sizeof(input)); cmd = input; /* skip leading whitespace. */ while(*cmd == ' ') cmd++; if(*cmd) { /* here, some command entered */ opt = get_next_arg(cmd); /* dispatch command */ 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(); /* does not return */ } command_boot(NULL); /* * command_boot() returns only if it failed to boot. * we enter to boot menu in this case. */ bootmenu(); return 0; }