/* $Header:bootxx.c 12.0$ */
/* $ACIS:bootxx.c 12.0$ */
/* $Source: /ibm/acis/usr/sys/standca/RCS/bootxx.c,v $ */

#ifndef lint
static char *rcsid = "$Header:bootxx.c 12.0$";
#endif

/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1986,1987
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:bootxx.c 12.0$ */
/* $ACIS:bootxx.c 12.0$ */
/* $Source: /ibm/acis/usr/sys/standca/RCS/bootxx.c,v $ */

#include "param.h"
#include "inode.h"
#include "fs.h"
#include "vm.h"
#include <a.out.h>
#include "saio.h"
#include "reboot.h"

#include "../machine/rdb.h"
#define POST_END	(POST_START+POST_SIZE)       /* next location after the POST */

#define BASEMASK 0x0fff0000	       /* mask for calculating base address */

char bootprog[36] = "xx(0,0)boot";

/*
 * Boot program... arguments passed in r10 and r11
 * are passed through to the full boot program.
 */

#undef main

main()
{
	register howto, devtype;	/* howto=r11, devtype=r10 */
	int io;

#ifdef lint
	howto = 0; devtype = 0;
#endif
	io = open(bootprog, 0);
	if (io >= 0)
		copyunix(howto, io);
	else
		bootprog[3]++;		/* try another disk */
	exit(6);
}


/*ARGSUSED*/
copyunix(howto, io)
	register howto, io;
{
	struct exec x;
	register int i;
	char *addr;
	register int baseaddr;	       /* segment base address */
	extern char end;

	i = read(io, (char *) & x, sizeof x);
	if (i != sizeof x ||
	    (x.a_magic != 0407 && x.a_magic != 0413 && x.a_magic != 0410))
		exit(1);
	baseaddr = ((int)x.a_entry) & BASEMASK;	/* same base as entry */
/*
 * following allows boot to boot itself without overwritting itself (which
 * tends not to work very well).
 */
	if (baseaddr == (BASEMASK & (int)main)) {
		baseaddr ^= 0x80000;    /* hope it's relocatable! */
		x.a_entry = (x.a_entry & ~BASEMASK) + baseaddr;
	}
	{
		register int size = x.a_text + x.a_data + x.a_bss;

		if (baseaddr < (BASEMASK & (int)main) && baseaddr + size > (int) & end)
			exit(2);
	}
	if (x.a_magic == 0413 && lseek(io, NBPG, 0) == -1)
		goto shread;

	/*
	 * protect the POST by splitting up any read the crosses the POST
	 * into three reads (refusing to read data into the POST.
	 */
	if (baseaddr <= POST_START && x.a_text > POST_END) {
		/* text will span the POST */
		register int len = POST_START - baseaddr;
		register char *p;
		char buff[POST_END - POST_START]; /* data for POST */

		if (read(io, (char *)baseaddr, len) != len)
			goto shread;   /* read up to POST */
		if (read(io, buff, POST_END - POST_START) != POST_END - POST_START)
			goto shread;   /* read POST */
		for (len = 0, p = buff; p < buff + POST_END - POST_START; ++p)
			if (*p)
				++len;
		len = x.a_text - (POST_END - baseaddr);
		if (read(io, (char *)POST_END, len) != len)
			goto shread;
	} else if (baseaddr + x.a_text < POST_END)
		_display(0x96);
	else			       /* fall thru to the normal case */

	if (read(io, (char *)baseaddr, x.a_text) != x.a_text)
		goto shread;
	addr = (char *)x.a_text + baseaddr;
	if (x.a_magic == 0413 || x.a_magic == 0410)
		while ((int)addr & CLOFSET)
			*addr++ = 0;
	if (read(io, addr, x.a_data) != x.a_data)
		goto shread;
	addr += x.a_data;
	x.a_bss += 8 * 512;	       /* slop */
	for (i = 0; i < x.a_bss; i++)
		*addr++ = 0;
	x.a_entry &= 0x0fffffff;       /* remove segment number */
	if (*(short *)x.a_entry != 0)
		callabs(x.a_entry,howto,0);
	exit(0);
shread:
	exit(3);
}
