/*-=-=-=-=-=-=-=-=-=-=-=- RCCL/RCI Notice of Copyright -=-=-=-=-=-=-=-=-=-=-*
 *									    *
 *	Copyright (C) 1987, 1991 by Mike Parker.			    *
 *									    *
 *	Information on copyright permissions, as well as a complete	    *
 *	disclaimer of warranty, is given in the file COPYRIGHT.		    *
 *									    *
 *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/

/*
 * Usage:
 *
 *	sboot2 <cpu> <file>
 *
 * <cpu> is 1, 2, or 3 indicating one of the three possible auxiliary
 *  cpus.  <file> is a file containing a kernel to be booted by sending
 *  messages to boot2.
 */

#include <stdio.h>
#include <a.out.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>

#include "../sys/rciext/kaioctl.h"
#include "../sys/rciext/kamsgs.h"

char *sbrk();

extern char **argvec;

#define MINCPU 1
#define MAXCPU 3

int cpu;
int bootfd;
char *bootfn;
char kadev[64];
char kafmt[] = "/dev/ka%d";
int kafd;
struct exec hdr;
struct blkdesc msgdesc;
char bootmsg[1024];

main(ac,av)
int ac;
char **av;
{
 if (ac != 3)
  { fprintf(stderr,"Usage: %s <cpu> <bootfile>\n",argvec[0]);
    exit(1);
  }
 cpu = xatoi(av[1]);
 sprintf(kadev,kafmt,cpu);
 kafd = open(kadev,O_RDWR,0);
 if (kafd < 0)
  { fprintf(stderr,"%s: can't open %s: ",argvec[0],kadev);
    perror((char *)0);
    exit(1);
  }
 bootfn = av[2];
 bootfd = open(bootfn,O_RDONLY,0);
 if (bootfd < 0)
  { fprintf(stderr,"%s: can't open %s: ",argvec[0],bootfn);
    perror((char *)0);
    exit(1);
  }
 if (read(bootfd,(char *)&hdr,sizeof(hdr)) != sizeof(hdr))
  { fprintf(stderr,"%s: can't read exec header from %s\n",argvec[0],bootfn);
    exit(1);
  }
 if (N_BADMAG(hdr))
  { fprintf(stderr,"%s: %s: Bad magic number\n",argvec[0],bootfn);
    exit(1);
  }
 sendtext();
 senddata();
 sendexec();
 exit(0);
}

sendtext()
{
 int left;
 int caddr;
 int n;

 left = hdr.a_text;
 lseek(bootfd,(off_t)N_TXTOFF(hdr),L_SET);
 caddr = 0;
 while (left > 0)
  { n = (left < sizeof(bootmsg)-13) ? left : sizeof(bootmsg)-13;
    bootmsg[0] = MSG_BOOTDATA;
    *(int *)&bootmsg[1] = n + 13;
    *(int *)&bootmsg[5] = caddr;
    *(int *)&bootmsg[9] = n;
    if (read(bootfd,&bootmsg[13],n) != n)
     { fprintf(stderr,
		"%s: can't read text (%d bytes, core address %d) from %s\n",
				argvec[0],n,caddr,bootfn);
       exit(1);
     }
    msgdesc.size = n + 13;
    msgdesc.addr = &bootmsg[0];
    if (ioctl(kafd,KAIOC_WMSGBUF,&msgdesc) < 0)
     { perror("KAIOC_WMSGBUF ioctl");
       exit(1);
     }
    left -= n;
    caddr += n;
  }
}

senddata()
{
 int left;
 int caddr;
 int n;

 left = hdr.a_data;
 if (hdr.a_magic == OMAGIC)
  { caddr = hdr.a_text;
  }
 else
  { caddr = (hdr.a_text + 1023) & ~1023;
  }
 while (left > 0)
  { n = (left < sizeof(bootmsg)-13) ? left : sizeof(bootmsg)-13;
    bootmsg[0] = MSG_BOOTDATA;
    *(int *)&bootmsg[1] = n + 13;
    *(int *)&bootmsg[5] = caddr;
    *(int *)&bootmsg[9] = n;
    if (read(bootfd,&bootmsg[13],n) != n)
     { fprintf(stderr,
		"%s: can't read data (%d bytes, core address %d) from %s\n",
				argvec[0],n,caddr,bootfn);
       exit(1);
     }
    msgdesc.size = n + 13;
    msgdesc.addr = &bootmsg[0];
    if (ioctl(kafd,KAIOC_WMSGBUF,&msgdesc) < 0)
     { perror("KAIOC_WMSGBUF ioctl");
       exit(1);
     }
    left -= n;
    caddr += n;
  }
 left = hdr.a_bss;
 while (left > 0)
  { n = (left < sizeof(bootmsg)-13) ? left : sizeof(bootmsg)-13;
    bootmsg[0] = MSG_BOOTDATA;
    *(int *)&bootmsg[1] = n + 13;
    *(int *)&bootmsg[5] = caddr;
    *(int *)&bootmsg[9] = n;
    bzero(&bootmsg[13],n);
    msgdesc.size = n + 13;
    msgdesc.addr = &bootmsg[0];
    if (ioctl(kafd,KAIOC_WMSGBUF,&msgdesc) < 0)
     { perror("KAIOC_WMSGBUF ioctl");
       exit(1);
     }
    left -= n;
    caddr += n;
  }
}

sendexec()
{
 bootmsg[0] = MSG_BOOTEXEC;
 *(int *)&bootmsg[1] = 9;
 *(int *)&bootmsg[5] = hdr.a_entry + 2; /* skip entry mask */
 msgdesc.size = 9;
 msgdesc.addr = &bootmsg[0];
 if (ioctl(kafd,KAIOC_WMSGBUF,&msgdesc) < 0)
  { perror("KAIOC_WMSGBUF ioctl");
    exit(1);
  }
}
