/*      $NetBSD: bootxx.c,v 1.17 2016/06/11 06:28:07 dholland Exp $     */

/*
* Copyright (c) 1995 Waldi Ravens.
* 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.
* 3. All advertising materials mentioning features or use of this software
*    must display the following acknowledgement:
*        This product includes software developed by Waldi Ravens.
* 4. The name of the author may not be used to endorse or promote products
*    derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/

#define boot_BSD        bsd_startup

#include <lib/libsa/stand.h>
#include <atari_stand.h>
#include <libkern.h>
#include <tosdefs.h>
#include <sys/boot_flag.h>
#include <sys/exec.h>
#include <sys/reboot.h>
#include <machine/cpu.h>

typedef int      (*bxxx_t)(void *, void *, struct osdsc *);

int     bootxx(void *, void *, int);
void    boot_BSD(struct kparamb *) __attribute__((noreturn));
int     bootxxx(void *, void *, struct osdsc *);
int     load_booter(struct osdsc *);
int     usr_info(struct osdsc *);

#define BOOTXXX_MAXSIZE (64 * 1024)
#define HEAPSIZE        (64 * 1024)     /* should be >32KB for ffs blocksize */
#define HEAPSTART       (LOADADDR3 + BOOTXXX_MAXSIZE)
#define HEAPEND         (HEAPSTART + HEAPSIZE)

int
bootxx(void *readsector, void *disklabel, int autoboot)
{
       static osdsc_t  os_desc;
       extern char     end[], edata[];
       osdsc_t         *od = &os_desc;
       bxxx_t          bootxxx = (bxxx_t)(LOADADDR3);

       memset(edata, 0, end - edata);
       setheap((void *)HEAPSTART, (void *)HEAPEND);

       printf("\033v\nNetBSD/atari secondary bootloader"
                                               " ($Revision: 1.17 $)\n\n");

       if (init_dskio(readsector, disklabel, -1))
               return -1;

       for (;;) {
               od->rootfs = 0;                 /* partition a */
               od->osname = "/netbsd";
               od->ostype = &od->osname[1];
               od->boothowto = (RB_RDONLY);

               if (!autoboot) {
                       int     pref;

                       od->boothowto = (RB_RDONLY|RB_SINGLE);
                       pref = usr_info(od);
                       if (pref < 0)
                               continue;
                       if (pref > 0)
                               return pref;
               }
               autoboot = 0;                   /* in case auto boot fails */

               if (init_dskio(readsector, disklabel, od->rootfs))
                       continue;

               if (load_booter(od))
                       continue;

               (*bootxxx)(readsector, disklabel, od);
       }
       /* NOTREACHED */
}


int
usr_info(osdsc_t *od)
{
       static char     line[800];
       char            c, *p = line;

       printf("\nEnter os-type [.%s] root-fs [:a] kernel [%s]"
              " options [none]:\n\033e", od->ostype, od->osname);
       kgets(p, sizeof(line));
       printf("\033f");

       for (;;) {
               while (isspace(*p))
                       *p++ = '\0';

               switch (*p++) {
               case '\0':
                       goto done;
               case ':':
                       if ((c = *p) >= 'a' && c <= 'z')
                               od->rootfs = c - 'a';
                       else if (c >= 'A' && c <= 'Z')
                               od->rootfs = c - ('A' - 27);
                       else
                               return -1;

                       if (!od->rootfs)
                               break;
                       *p = 'b';
                       /* FALLTHROUGH */
                 case '-':
                       if ((c = *p) == 'a')
                               od->boothowto &= ~RB_SINGLE;
                       else if (c == 'b')
                               od->boothowto |= RB_ASKNAME;
                       else
                               BOOT_FLAG(c, od->boothowto);
                       break;
                 case '.':
                       od->ostype = p;
                       break;
                 case '/':
                       od->osname = --p;
                       break;
                 default:
                       return -1;
               }

               while ((c = *p) && !isspace(c))
                       p += 1;
       }

done:
       c = od->ostype[0];
       if (isupper(c))
               c = tolower(c);

       switch (c) {
       case 'n':               /* NetBSD */
               return 0;
       case 'l':               /* Linux  */
               return 0x10;
       case 'a':               /* ASV    */
               return 0x40;
       case 't':               /* TOS    */
               return 0x80;
       default:
               return -1;
       }
}

int
load_booter(osdsc_t *od)
{
       int             fd = -1;
       u_char          *bstart = (u_char *)(LOADADDR3);
       int             bsize;
       char            *fname;
       char            *boot_names[] = {       /* 3rd level boot names   */
                               "/boot.atari",  /* in order of preference */
                               "/boot",
                               "/boot.ata",
                               NULL };         /* NULL terminated!       */

       /*
        * Read booter's exec-header.
        */
       for (fname = boot_names[0]; fname != NULL; fname++) {
               if ((fd = open(fname, 0)) < 0)
                       printf("Cannot open '%s'\n", fname);
               else
                       break;
       }
       if (fd < 0)
               return -1;
       while ((bsize = read(fd, bstart, 1024)) > 0) {
               bstart += bsize;
       }
       close(fd);
       return 0;
}

void
_rtt(void)
{

       printf("Halting...\n");
       for (;;)
               ;
}