/* $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 */

#ident	"$Header: bootxx.c 1.5 89/08/22 $"

/* $Log:	bootxx.c,v $
 */

#include <sys/types.h>
#include <sys/param.h>
#include <sys/ufsinode.h>
#include <sys/ufsfilsys.h>
#include <sys/cfg.h>
#include <a.out.h>
#include "saio.h"

caddr_t	calloc();

#define COFFHDR	sizeof(struct filehdr)+sizeof(struct aouthdr)+\
			(4 * sizeof(struct scnhdr))
#ifdef	AT386
char bootprog[] = "xx(0,0)boot";
#endif

/*
 * 8K byte boot program that loads /boot.
 */
main()
{
	register int io;
#ifndef	AT386
	register char *s;
	struct config_desc *cd = (struct config_desc *)CD_LOC;
	char *bootprog;
	char *index();

	bootprog = (char *)calloc(cd->c_bname_size);
	bcopy(cd->c_boot_name, bootprog, cd->c_bname_size);
	s = index(bootprog, ')') + 1;
	if (devsw[0].dv_flags & D_TAPE)
		strcpy(index(bootprog, ','), ",1)");	/* file1 for tapes */
	else
		strcpy(s, "boot");
#endif
	printf("loading %s\n", bootprog);
	io = open(bootprog, 0);
	if (io >= 0)
		copyunix(io);
	_stop("boot failed");
}

/* to make bootstraps smaller */
exit() 
{
}

/* to make bootstraps smaller */
_stop(s)
	char *s;
{

	printf("%s\n", s);
	for(;;)
		/* spin */;
}


/*
 * Define a structure that includes both main header and extra header so the
 * entire header information for the file may be read at once.
 * Also define a structure for reading section headers into.
 */
struct headers {
	struct filehdr mainhdr;
	struct aouthdr secondhdr;
};

copyunix(io)
	int io;
{
	int	length,
		n,
		offset,
		no_of_nscns;
	long	entry,
		text_size,
		text_start,
		data_size,
		data_start;
	struct	scnhdr	*section;
	struct	headers *head;

	/*
	 * start reading file at 1K boundary past end of allocated memory.
	 */
	callocrnd(1024);
	offset = (int)calloc(0);
	n = roundup(COFFHDR, DEV_BSIZE);
	head = (struct headers *)offset;

	/* 
	 *	read headers and check magic number
	 */
	if (read(io, head, n) != n)
		goto sread;
	if (head->mainhdr.f_magic != I386MAGIC)
		_stop("Bad a.out magic number");
	entry = head->secondhdr.entry;

	/*
	 *	read all the section headers noting
	 *	text, data, and bss information
	 */
	no_of_nscns = head->mainhdr.f_nscns;
	section = (struct scnhdr *)(offset + sizeof(struct headers));
	for ( ; no_of_nscns-- > 0; section ++) {
		if (section->s_flags & STYP_TEXT) {
			text_size = section->s_size;
			text_start = section->s_vaddr;
		}
		else if (section->s_flags & STYP_DATA) {
			data_size = section->s_size;
			data_start = section->s_vaddr;
		}
		else
			continue;
	}

	/*
	 *	load text image
	 */
	n = roundup(text_size, DEV_BSIZE);
	if (read(io, offset+text_start, n) != n)
		goto sread;

	/*
	 *	load data image
	 */
	if (read(io, offset+data_start, data_size) != data_size)
		goto sread;

	/*
	 *	exec new program over ourselves
	 */
	if (text_start + text_size > data_start + data_size)
		length = text_start + text_size;
	else
		length = data_start + data_size;
	gsp(offset + (int)CD_STAND_ADDR, (caddr_t)CD_STAND_ADDR,
		length-(int)CD_STAND_ADDR, entry);
	/*NOTREACHED*/
sread:
	_stop("short read");
}
