/*      $NetBSD: init_main.c,v 1.17 2024/09/24 11:17:54 rin Exp $       */

/*
* Copyright (c) 1992 OMRON Corporation.
*
* This code is derived from software contributed to Berkeley by
* OMRON Corporation.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
*    must display the following acknowledgement:
*      This product includes software developed by the University of
*      California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
*    may be used to endorse or promote products derived from this software
*    without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
*      @(#)init_main.c 8.2 (Berkeley) 8/15/93
*/
/*
* Copyright (c) 1992, 1993
*      The Regents of the University of California.  All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* OMRON Corporation.
*
* 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.
* 3. Neither the name of the University nor the names of its contributors
*    may be used to endorse or promote products derived from this software
*    without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
*      @(#)init_main.c 8.2 (Berkeley) 8/15/93
*/

#include <sys/param.h>
#include <sys/boot_flag.h>
#include <machine/cpu.h>
#include <luna68k/stand/boot/samachdep.h>
#include <luna68k/stand/boot/romvec.h>
#include <luna68k/stand/boot/status.h>
#include <lib/libsa/loadfile.h>
#ifdef SUPPORT_ETHERNET
#include <lib/libsa/dev_net.h>
#endif

static int get_plane_numbers(void);
static int reorder_dipsw(int);

int cpuspeed;   /* for DELAY() macro */
int hz = 60;
int machtype;
char default_file[64];
const char *default_bootdev;
int default_unit;

#define VERS_LOCAL      "Phase-31"

int nplane;

/* for command parser */

#define BUFFSIZE 100
#define MAXARGS  30

char buffer[BUFFSIZE];

int   argc;
char *argv[MAXARGS];

#define BOOT_TIMEOUT 10
int boot_timeout = BOOT_TIMEOUT;

static const char prompt[] = "boot> ";

/*
* PROM monitor's boot device info
*/

/* LUNA-I monitor's bootinfo structure */
/* This bootinfo data address is investigated on ROM Ver4.22 and Ver4.25 */
#define LUNA1_BOOTINFOADDR      0x000008c0
struct luna1_bootinfo {
       uint8_t bi_xxx1[3];     /* 0x08c0: ??? */
       uint8_t bi_device;      /* 0x08c3: boot device */
#define LUNA1_BTDEV_DK  0               /* Hard-Disk */
#define LUNA1_BTDEV_FB  1               /* Floppy-Disk */
#define LUNA1_BTDEV_SD  2               /* Streamer-Tape */
#define LUNA1_BTDEV_P0  3               /* RS232c */
#define LUNA1_BTDEV_ET  4               /* Ether-net */
#define LUNA1_NBTDEV    5

       struct {
               uint8_t bd_xxx1;        /*  0: ??? */
               uint8_t bd_boot;        /*  1: 1 == booted */
               char    bd_name[2];     /*  2: device name (dk, fb, sd ... ) */
               uint8_t bd_drv;         /*  4: drive number (not ID) */
               uint8_t bd_xxx2;        /*  5: ??? */
               uint8_t bd_xxx3;        /*  6: ??? */
               uint8_t bd_part;        /*  7: dk partition / st record # */
               uint8_t bd_xxx4[4];     /*  8: ??? */
               uint8_t bd_xxx5[4];     /* 12: ??? */
       } bi_devinfo[LUNA1_NBTDEV];
} __packed;

/* LUNA-II monitor's bootinfo structure */
/* This bootinfo data address is investigated on ROM Version 1.11 */
#define LUNA2_BOOTINFOADDR      0x00001d80
struct luna2_bootinfo {
       uint8_t bi_xxx1[13];    /* 0x1d80: ??? */
       uint8_t bi_device;      /* 0x1d8d: boot device */
#define LUNA2_BTDEV_DK  0               /* Hard-Disk */
#define LUNA2_BTDEV_FT  1               /* Floppy-Disk */
#define LUNA2_BTDEV_SD  2               /* Streamer-Tape */
#define LUNA2_BTDEV_P0  3               /* RS232c */
#define LUNA2_NBTDEV    4

       struct {
               uint8_t bd_xxx1;        /*  0: ??? */
               uint8_t bd_boot;        /*  1: 1 == booted */
               char    bd_name[4];     /*  2: device name (dk, ft, sd ... ) */
               uint8_t bd_xxx2;        /*  6: ??? */
               uint8_t bd_ctlr;        /*  7: SCSI controller number */
               uint8_t bd_id;          /*  8: SCSI ID number */
               uint8_t bd_xxx3;        /*  9: device number index? */
               uint8_t bd_xxx4;        /* 10: ??? */
               uint8_t bd_part;        /* 11: dk partition / st record # */
               uint8_t bd_xxx5[4];     /* 12: ??? */
               uint8_t bd_xxx6[4];     /* 16: ??? */
       } bi_devinfo[LUNA2_NBTDEV];
} __packed;

/* #define BTINFO_DEBUG */

void
main(void)
{
       int i, status = ST_NORMAL;
       const char *machstr;
       const char *bootdev;
       uint32_t howto;
       int unit, part;
       int bdev, ctlr, id;

       /*
        * Initialize the console before we print anything out.
        */
       if (cputype == CPU_68030) {
               machtype = LUNA_I;
               machstr  = "LUNA-I";
               cpuspeed = MHZ_25;
               hz = 60;
       } else {
               machtype = LUNA_II;
               machstr  = "LUNA-II";
               cpuspeed = MHZ_25 * 2;  /* XXX */
               hz = 100;
       }

       nplane = get_plane_numbers();

       cninit();

       printf("\n");
       printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev);
       printf(">> (based on Stinger ver 0.0 [%s])\n", VERS_LOCAL);
       printf("\n");

       i = ROM_memsize;
       printf("Machine model   = %s\n", machstr);
       printf("Physical Memory = 0x%x  ", i);
       i >>= 20;
       printf("(%d MB)\n", i);
       printf("\n");

       /*
        * IO configuration
        */

#ifdef SUPPORT_ETHERNET
       try_bootp = 1;
#endif

       find_devs();
       printf("\n");

       /* use sd(0,0) for the default boot device */
       bootdev = "sd";
       unit = 0;
       part = 0;

/*
* - LUNA1_BOOTINFOADDR is in the 0-th page [0, 0x1000), which causes
*   -Warray-bounds for GCC12 and later.
* - LUNA2_BOOTINFOADDR is also in the 0-th page, if we switch to
*   8KB page.
*/
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warray-bounds"

       if (machtype == LUNA_I) {
               const struct luna1_bootinfo *bi1 = (void *)LUNA1_BOOTINFOADDR;

               bdev = bi1->bi_device;
               switch (bdev) {
               case LUNA1_BTDEV_DK:
                       /* note: bd_drv is not SCSI ID */
                       ctlr = 0;
                       id   = 6 - bi1->bi_devinfo[bdev].bd_drv;
                       unit = UNIT(ctlr, id);
                       break;
               case LUNA1_BTDEV_ET:
                       bootdev = "le";
                       unit = 0;
                       break;
               default:
                       /* not supported */
                       break;
               }
#ifdef BTINFO_DEBUG
               printf("bi1->bi_device = 0x%02x\n", bi1->bi_device);
               printf("bi1->bi_devinfo[bdev].bd_boot = 0x%02x\n",
                   bi1->bi_devinfo[bdev].bd_boot);
               printf("bi1->bi_devinfo[bdev].bd_name = %c%c\n",
                   bi1->bi_devinfo[bdev].bd_name[0],
                   bi1->bi_devinfo[bdev].bd_name[1]);
               printf("bi1->bi_devinfo[bdev].bd_drv = 0x%02x\n",
                   bi1->bi_devinfo[bdev].bd_drv);
               printf("bi1->bi_devinfo[bdev].bd_part = 0x%02x\n",
                   bi1->bi_devinfo[bdev].bd_part);
#endif
       } else {
               const struct luna2_bootinfo *bi2 = (void *)LUNA2_BOOTINFOADDR;

               bdev = bi2->bi_device;
               switch (bdev) {
               case LUNA2_BTDEV_DK:
                       ctlr = bi2->bi_devinfo[bdev].bd_ctlr;
                       id   = bi2->bi_devinfo[bdev].bd_id;
                       unit = UNIT(ctlr, id);
                       break;
               default:
                       /* not supported */
                       break;
               }
#ifdef BTINFO_DEBUG
               printf("bi2->bi_device = 0x%02x\n", bi2->bi_device);
               printf("bi2->bi_devinfo[bdev].bd_boot = 0x%02x\n",
                   bi2->bi_devinfo[bdev].bd_boot);
               printf("bi2->bi_devinfo[bdev].bd_name = %s\n",
                   bi2->bi_devinfo[bdev].bd_name);
               printf("bi2->bi_devinfo[bdev].bd_ctlr = 0x%02x\n",
                   bi2->bi_devinfo[bdev].bd_ctlr);
               printf("bi2->bi_devinfo[bdev].bd_id = 0x%02x\n",
                   bi2->bi_devinfo[bdev].bd_id);
               printf("bi2->bi_devinfo[bdev].bd_part = 0x%02x\n",
                   bi2->bi_devinfo[bdev].bd_part);
#endif
       }

#pragma GCC diagnostic pop

       snprintf(default_file, sizeof(default_file),
           "%s(%d,%d)%s", bootdev, unit, part, "netbsd");
       default_bootdev = bootdev;
       default_unit = unit;

       howto = reorder_dipsw(dipsw2);

       if ((howto & 0xFE) == 0) {
               char c;

               printf("Press return to boot now,"
                   " any other key for boot menu\n");
               printf("booting %s - starting in ", default_file);
               c = awaitkey("%d seconds. ", boot_timeout, true);
               if (c == '\r' || c == '\n' || c == 0) {
                       printf("auto-boot %s\n", default_file);
                       bootnetbsd(default_file, 0);
               }
       }

       /*
        * Main Loop
        */

       printf("type \"help\" for help.\n");

       do {
               memset(buffer, 0, BUFFSIZE);
               if (getline(prompt, buffer) > 0) {
                       argc = getargs(buffer, argv,
                           sizeof(argv) / sizeof(char *));

                       status = parse(argc, argv);
                       if (status == ST_NOTFOUND)
                               printf("Command \"%s\" is not found !!\n",
                                   argv[0]);
               }
       } while (status != ST_EXIT);

       exit(0);
}

static int
get_plane_numbers(void)
{
       int r = ROM_plane;
       int n = 0;

       for (; r ; r >>= 1)
               if (r & 0x1)
                       n++;

       return n;
}

static int
reorder_dipsw(int dipsw)
{
       int i, sw = 0;

       for (i = 0; i < 8; i++) {
               if ((dipsw & 0x01) == 0)
                       sw += 1;

               if (i == 7)
                       break;

               sw <<= 1;
               dipsw >>= 1;
       }

       return sw;
}