/* $NetBSD: boot.c,v 1.7 2008/07/16 14:45:17 tsutsui Exp $ */ /*- * Copyright (c) 2004 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by UCHIYAMA Yasushi. * * 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 #include #include "local.h" #include "cmd.h" #include "common.h" #include #include #include #include "console.h" extern const char bootprog_name[]; extern const char bootprog_rev[]; extern const char bootprog_kernrev[]; struct cmd_batch_tab cmd_batch_tab[] = { /* func argc argp... */ #if 0 { cmd_boot, 1, { "mem:", 0, 0, 0, 0, 0, 0 } }, { cmd_boot, 1, { "sd0k:netbsd", 0, 0, 0, 0, 0, 0 } }, { cmd_load_binary, 1, { "0x80001000", 0, 0, 0, 0, 0, 0 } }, { cmd_jump, 2, { "0x80001000", "0x80001000", 0, 0, 0, 0, 0 } }, #endif { NULL, 0, { 0, 0, 0, 0, 0, 0, 0 } } /* terminate */ }; struct ipl_args ipl_args; struct device_capability DEVICE_CAPABILITY; void set_device_capability(void); bool guess_boot_kernel(char *, size_t, int); extern int kernel_binary_size; void main(int a0, int v0, int v1) { extern char edata[], end[]; char boot_kernel[32]; char *args[CMDARG_MAX]; int i; memset(edata, 0, end - edata); /* Save args for chain-boot to iopboot */ ipl_args.a0 = a0; ipl_args.v0 = v0; ipl_args.v1 = v1; console_init(); printf("\n"); printf("%s boot, Revision %s (from NetBSD %s)\n", bootprog_name, bootprog_rev, bootprog_kernrev); /* Inquire IPL activated device */ set_device_capability(); if (!guess_boot_kernel(boot_kernel, sizeof boot_kernel, 0)) goto prompt; printf( ">> Press return to boot now, any other key for boot console.\n"); for (i = 5000; i >= 0; i--) { int c; if (i % 1000 == 0) printf("booting %s - starting %d\r", boot_kernel, i / 1000); if ((c = cnscan()) == -1) { delay(10); continue; } else if (c == '\r') break; else goto prompt; } printf("\n[non-interactive mode]\n"); args[0] = "boot"; args[1] = boot_kernel; cmd_boot(2, args, false); prompt: printf("\ntype \"help\" for help.\n"); console_cursor(true); prompt(); /* NOTREACHED */ } bool guess_boot_kernel(char *name, size_t len, int pri) { extern struct vtoc_sector vtoc; struct ux_partition *partition; int i, unit; if (!DEVICE_CAPABILITY.active) return false; unit = DEVICE_CAPABILITY.booted_unit; switch (DEVICE_CAPABILITY.booted_device) { default: return false; case NVSRAM_BOOTDEV_FLOPPYDISK: strncpy(name, "fd:netbsd", len); /* ustarfs */ return true; case NVSRAM_BOOTDEV_HARDDISK: snprintf(name, len, "sd%d:netbsd", unit); /* ustarfs */ if (!read_vtoc()) return true; partition = vtoc.partition; for (i = 0; i < VTOC_MAXPARTITIONS; i++, partition++) { if (partition->tag != __VTOC_TAG_BSDFFS) continue; /* ffs */ snprintf(name, len, "sd%d%c:netbsd", unit, 'a' + i); return true; } return true; case NVSRAM_BOOTDEV_CGMT: break; case NVSRAM_BOOTDEV_NETWORK: /*FALLTHROUGH*/ case NVSRAM_BOOTDEV_NETWORK_T_AND_D: if (kernel_binary_size) { strncpy(name, "mem:", len); /* datafs */ return true; } if (DEVICE_CAPABILITY.network_enabled) { strncpy(name, "nfs:netbsd", len); /* nfs */ return true; } break; } return false; } int cmd_info(int argc, char *argp[], int interactive) { extern char _ftext[], _etext[], _fdata[], _edata[]; extern char _fbss[], end[]; uint32_t m; int i, size, total; struct sbdinfo *sbd = SBD_INFO; printf("\n>> %s boot, Revision %s (from NetBSD %s) <<\n", bootprog_name, bootprog_rev, bootprog_kernrev); printf("IPL args: 0x%x 0x%x 0x%x\n", ipl_args.a0, ipl_args.v0, ipl_args.v1); printf("\ttext : %p-%p\n\tdata : %p-%p\n\t" "bss : %p-%p\n\tstack: %p\n\theap : %p\n", _ftext, _etext, _fdata, _edata, _fbss, end, _ftext, end); m = ipl_args.v1; total = 0; printf("Memory Area:\n\t"); for (i = 0; i < 8; i++, m >>= 4) { size = m & 0xf ? ((m & 0xf) << 4) : 0; total += size; if (size) printf("M%d=%dMB ", i, size); } printf(" total %dMB\n", total); printf("Board Revision:\n"); printf("\tmachine=0x%x, ", sbd->machine); printf("model=0x%x\n", sbd->model); printf("\tpmmu=%d, ", sbd->mmu); printf("cache=%d, ", sbd->cache); printf("panel=%d, ", sbd->panel); printf("fdd=%d\n", sbd->fdd); printf("\tcpu=%d, fpp=%d, fpa=%d, iop=%d\n", sbd->cpu, sbd->fpp, sbd->fpa, sbd->iop); printf("\tclock=%d\n", sbd->clock); printf("\tipl=%d, cpu_ex=%d, fpp_ex=%d\n", sbd->ipl, sbd->cpu_ex, sbd->fpp_ex); printf("\tkbms=%d, sio=%d, battery=%d, scsi=%d\n", sbd->kbms, sbd->sio, sbd->battery, sbd->scsi); printf("model name=%s\n", sbd->model_name); return 0; } int cmd_reboot(int argc, char *argp[], int interactive) { int bootdev = -1; if (argc > 1) bootdev = strtoul(argp[1], 0, 0); /* next boot device. */ if (bootdev != NVSRAM_BOOTDEV_FLOPPYDISK && bootdev != NVSRAM_BOOTDEV_HARDDISK && bootdev != NVSRAM_BOOTDEV_CGMT && bootdev != NVSRAM_BOOTDEV_NETWORK) { printf("invalid boot device."); bootdev = -1; } switch (SBD_INFO->machine) { case MACHINE_TR2A: if (bootdev != -1) *(uint8_t *)0xbe493030 = bootdev; *(volatile uint32_t *)0xbe000064 |= 0x80000000; *(volatile uint8_t *)0xba000004 = 1; *(uint8_t *)0xbfbffffc = 255; break; case MACHINE_TR2: if (bootdev != -1) *(uint8_t *)0xbb023030 = bootdev; *(volatile uint32_t *)0xbfb00000 |= 0x10; break; default: ROM_MONITOR(); } while (/*CONSTCOND*/1) ; /* NOTREACHED */ return 0; } void set_device_capability(void) { const char *devname[] = { "Floppy disk", "Unknown", "Hard disk", "Unknown", "CGMT", "Unknown", "Network", "Unknown", "Network T&D" }; int booted_device, booted_unit, fd_format; boot_device(&booted_device, &booted_unit, &fd_format); if (booted_device > NVSRAM_BOOTDEV_MAX || booted_device < NVSRAM_BOOTDEV_MIN) { printf( "invalid booted device. NVSRAM information isn't valid\n"); } else { DEVICE_CAPABILITY.booted_device = booted_device; } DEVICE_CAPABILITY.booted_unit = booted_unit; switch (SBD_INFO->machine) { case MACHINE_TR2A: DEVICE_CAPABILITY.active = true; /* boot has LANCE driver */ DEVICE_CAPABILITY.network_enabled = true; break; case MACHINE_TR2: DEVICE_CAPABILITY.active = true; break; default: DEVICE_CAPABILITY.active = false; break; } DEVICE_CAPABILITY.fd_enabled = true; /* always enabled */ if (DEVICE_CAPABILITY.active) { /* * When NETWORK IPL, FD IPL doesn't activate ROM DISK routine. */ if (DEVICE_CAPABILITY.booted_device == NVSRAM_BOOTDEV_HARDDISK) DEVICE_CAPABILITY.disk_enabled = true; } printf("FD[%c] DISK[%c] NETWORK[%c] COMPILED[%c]\n", DEVICE_CAPABILITY.fd_enabled ? 'x' : '_', DEVICE_CAPABILITY.disk_enabled ? 'x' : '_', DEVICE_CAPABILITY.network_enabled ? 'x' : '_', kernel_binary_size ? 'x' : '_'); printf("booted from %s IPL", devname[DEVICE_CAPABILITY.booted_device]); if ((DEVICE_CAPABILITY.booted_device == NVSRAM_BOOTDEV_NETWORK) || (DEVICE_CAPABILITY.booted_device == NVSRAM_BOOTDEV_NETWORK_T_AND_D)) { printf("\n"); } else { printf(" unit %d\n", DEVICE_CAPABILITY.booted_unit); } } int cmd_test(int argc, char *argp[], int interactive) { /* MISC TEST ROUTINE */ extern int fdd_test(void); fdd_test(); #if 0 int i; printf("argc=%d\n", argc); for (i = 0; i < argc; i++) printf("[%d] %s\n", i, argp[i]); #endif #if 0 /* Recover my 360ADII NVSRAM.. */ uint8_t *p = (uint8_t *)0xbe490000; uint8_t *q = nvsram_tr2a; int i; for (i = 0; i < sizeof nvsram_tr2a; i++) { *p = *q; p += 4; q += 1; } #endif #if 0 /* ROM PUTC test */ char a[]= "ohayotest!"; int i; for (i = 0; i < 10; i++) ROM_PUTC(120 + i * 12, 24 * 10, a[i]); #endif #if 0 /* ROM SCSI disk routine test TR2 */ uint8_t buf[512*2]; uint8_t *p; int i; printf("type=%d\n", *(uint8_t *)0xbb023034); memset(buf, 0, sizeof buf); p = (uint8_t *)(((uint32_t)buf + 511) & ~511); i = ROM_DK_READ(0, 0, 1, p); printf("err=%d\n", i); for (i = 0; i < 64; i++) { printf("%x ", p[i]); if (((i + 1) & 0xf) == 0) printf("\n"); } #endif #if 0 /*XXX failed. */ __asm volatile( ".set noreorder;" "li $4, 2;" "mtc0 $4, $16;" /* Config */ "lui $4, 0xbfc2;" "jr $4;" "nop;" ".set reorder"); /* NOTREACHED */ #endif #if 0 /* FPU test */ { int v; __asm volatile( ".set noreorder;" "lui %0, 0x2000;" "mtc0 %0, $12;" /* Cu1 */ "nop;" "nop;" "cfc1 %0, $%1;" "nop;" "nop;" ".set reorder" : "=r"(v) : "i"(0)); printf("FPUId: %x\n", v); } #endif return 0; }