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

#if !defined(lint) && !defined(NO_RCS_HDRS)
static char *rcsid = "$Header:machdep.c 12.1$";
#endif

/*
 * Copyright (c) 1982, 1986 Regents of the University of California.
 * All rights reserved.  The Berkeley software License Agreement
 * specifies the terms and conditions for redistribution.
 *
 *	@(#)machdep.c	7.1 (Berkeley) 6/5/86
 */

#include "param.h"
#include "reg.h"
#include "pte.h"
#include "mmu.h"
#include "scr.h"
#include "debug.h"
#include "led.h"
#include "frame.h"
#include "systm.h"
#include "dir.h"
#include "user.h"
#include "kernel.h"
#include "map.h"
#include "vm.h"
#include "proc.h"
#include "buf.h"
#include "reboot.h"
#include "conf.h"
#ifdef VFS
#include "vnode.h"
#include "../ufs/inode.h"
#include "dnlc.h"
#else VFS
#include "inode.h"
#endif VFS
#include "file.h"
#include "text.h"
#include "clist.h"
#include "callout.h"
#include "cmap.h"
#include "mbuf.h"
#include "msgbuf.h"
#ifdef VFS
#ifdef QUOTA
#include "../ufs/quota.h"
#endif QUOTA
#else VFS
#include "../h/quota.h"
#endif VFS
#include "io.h"
#include "acct.h"
#ifdef	VICE
#include "rmtwd.h"
#endif
#include "clock.h"
#include "cpu.h"
#include "sigframe.h"
#ifdef ATR
#include "../ca_atr/pcif.h"
#endif ATR

/*
 * Support for X console emulator Event Q pseudo-device
 */
#include "xemul.h"
#if NXEMUL > 0
#include "../machinecons/xio.h"
#endif

/*
 * Support for AED simulated bitmap hack
 * we include this support if AED is configured and
 * either X10 support is specified or XWM is specified
 * (the latter is only for a single program that uses
 * the bitmap as shared memory and should eventually
 * disappear).
 */
#include "xtenemul.h"
#include "aed.h"
#if (NAED > 0 && NXTENEMUL > 0) || defined(XWM)
#include "../machinecons/apaaed.h"
#endif (NAED > 0 && NXTENEMUL > 0) || defined(XWM)

#include "post.h"

/*
 * Declare these as initialized data so we can patch them.
 */
int	nswbuf = 0;
#ifdef	NBUF
int	nbuf = NBUF;
#else
int	nbuf = 0;
#endif
#ifdef	BUFPAGES
int	bufpages = BUFPAGES;
#else
int	bufpages = 0;
#endif
char	ccr_default = { CCR_DEFAULT };		/* see ../machine/scr.h for bit definitions */
int	limitmem = 0;			/* patch to limit memory */

/*
 * Machine-dependent startup code
 * an important thing to remember is that 'physmem' is the count of the actual
 * physical memory; 'endmem' is the size that includes all of memory and
 * 'holelength' is the size of the hole in memory (if there is one).
 * maxmem is the page address of the actual effective end of memory.
 */
startup(firstaddr)
int firstaddr;
{
	int unixsize;
	register unsigned i, j;
	register caddr_t v;
	struct pte tmp_pte;
	int vpage, frame, skippages;
	int base, residual;
	extern char start, etext, edata, end;
	extern bufbase, buflimit;
	extern char coibm[];	/* Defined in locore */

	set_kernel_read_only();		/* protect kernel text */
	init_intr();			/* initialize interrupt system */
	delay_preadjust();		/* preadjust the delay counts */
	/*
	 * THIS SHOULD BE DONE BEFORE ANY PRINTFs OR PUTCHARs.
	 * otherwise any messages won't appear in the console message
	 * buffer. 'msgbufp' is used to prevent any messages that
	 * appear before this point (panics?) from causing more
	 * traps due to non-existance of the virtual address of the 
	 * message buffer.
	 * Grab a couple of real pages for the console message
	 * buffer at the end of core just before the HAT/IPT table
	 * and map them to a virtual address arbitrarily assigned
	 * in locore. Reduce available memory by the amount grabbed.
	 * Remember to map out the pages before remapping them!
	 * VAX PTEs can be totally ignored here, since the pages
	 * will never be remapped.
	 */
	maxmem -= btoc(sizeof (struct msgbuf));
	frame = maxmem;
	vpage = btop(&msgbuf);
	for (i = 0; i < btoc(sizeof (struct msgbuf)); i++) {
		mapout(&frame, 1);
		mapin(&tmp_pte, vpage++, PG_KW|frame++, 1);
	}
	msgbufp = (struct msgbuf *) vtop(&msgbuf);	/* mark it */


#if NXEMUL > 0
	/*
	 * Allocate space for the event pseudo-device.
	 */
	maxmem -= btoc(XBASIZE * NXEMUL);
	frame = maxmem;
	vpage = btop(MagicXBuffAddr);
	for (i = 0; i < btoc(XBASIZE * NXEMUL); i++) {
		mapout(&frame, 1);
		mapin(&tmp_pte, vpage++, PG_UW|PG_M|frame++, 1);
	}
#endif NXEMUL > 0

/* define simulated bit map if AED defined and using X10 or XWM defined */
#if (NAED > 0 && NXTENEMUL > 0) || defined(XWM)
	/*
	 * Allocate space for the bitmap for the simulated
	 * bitmapped AED display
	 */
	maxmem -= btoc(AED_BM_SIZE) + 1;
	frame = maxmem;
	vpage = btop(AED_BM_ADDR);
	for (i = 0; i < btoc(AED_BM_SIZE) + 1; i++) {
		mapout(&frame, 1);
		mapin(&tmp_pte, vpage++, PG_UW|PG_M|frame++, 1);
	}
#endif (NAED > 0 && NXTENEMUL > 0) || defined(XWM)


	/*
	 * Initialize the console port
	 */
	cnatch(0);
	/*
	 * reduce available memory if so desired to limitmem
	 */
	if (limitmem && maxmem > limitmem)
		maxmem = limitmem;
#ifdef ROMPC
#ifdef IBMRTPC
	/*
	 * check to see we have proper memory configuration 
	 */
	check_mem_config();
#endif IBMRTPC
#endif ROMPC

	/*
	 * Good {morning,afternoon,evening,night}.
	 */
	printf("%s", version);
	printf("\n%s\n",coibm);   /* this message is defined in locore */

#ifdef ATR
	printf("PS/2 %s code: %s\n\n", OS_STRING(config.os_type), config.version);
#endif ATR

#define MAXBUFFERPAGES 512	/* 1MB worth of buffers should be enough */
	/*
	 * Determine how many buffers to allocate
	 * and how many real pages to spread around the
	 * buffers. (Each buffer occupies MAXBSIZE virtual
	 * address space and has 0 to MAXBSIZE/CLBYTES
	 * real page (cluster) frames mapped to that space
	 * at any given time, according to need.)
	 * Use 10% of memory for the first 2 Meg, 5% of the remaining
	 * memory. Insure a minimum of 20 buffers.
	 * We allocate 2/3 as many swap buffer headers as file i/o buffers.
	 */
	if (bufpages == 0)
		if (physmem < (2 * 1024 * 1024 / NBPG))
			bufpages = physmem / 10 / CLSIZE;
		else
			bufpages = ((2 * 1024 * 1024 / NBPG + physmem) / 20) / CLSIZE;
	if (bufpages > MAXBUFFERPAGES)
		bufpages = MAXBUFFERPAGES;	/* max we can have */
	if (nbuf == 0) {
		/* Nominal 1.5 pages per buffer */
		nbuf = bufpages * 2 / 3;
		if (nbuf < 20)
			nbuf = 20;
	}

	/*
	 * Don't bite off more real pages than we can map!
	 */
	if (bufpages > nbuf * (MAXBSIZE / CLBYTES))
		bufpages = nbuf * (MAXBSIZE / CLBYTES);

	/*
	 * Grab "bufpages" real pages from the top of memory
	 * just below the pages we grabbed for the message
	 * buffer above. Remap these frames according to
	 * an algorithm which is well known in binit() in
	 * sys/init_main.c . Each buffer is allocated at
	 * least round(bufpages/nbuf) pages, and the first
	 * "bufpages%nbuf" buffers get an extra page each.
	 * ("skippages" is how many unmapped pages to skip.)
	 * The virtual address we map the buffers at is
	 * an arbitrary one in the system segment determined
	 * in locore. Again, VAX PTEs are not necessary since
	 * the pages we grab are permanently allocated to us
	 * (though we move them around between buffers).
	 */
	maxmem -= bufpages;
	base = bufpages / nbuf;
	residual = bufpages % nbuf;
	frame = maxmem;
	vpage = btop(&bufbase);
	skippages = (MAXBSIZE / CLBYTES) - (base + 1);

	for (i = 0; i < residual; i++) {
		for (j = 0; j < (base + 1) * CLSIZE; j++) {
			mapout(&frame, 1);
			mapin(&tmp_pte, vpage++, PG_KW|frame++, 1);
		}
		vpage += skippages;
	}
	skippages++;
	for (i = residual; i < nbuf; i++) {
		for (j = 0; j < base * CLSIZE; j++) {
			mapout(&frame, 1);
			mapin(&tmp_pte, vpage++, PG_KW|frame++, 1);
		}
		vpage += skippages;
	}

	/*
	 * Make sure we didn't crash into the user page tables.
	 */
	 if ( ((int *) ctob(vpage)) >= &buflimit)
		panic("startup buffers");
	/*
	 * Make sure we didn't crash into memory hole
	 */
	 if (ishole(vpage))
		panic("startup buffers hit hole");
	
	/*
	 * We allocate 1/2 as many swap buffer headers as
	 * file i/o buffers (don't ask me why).
	 */
	if (nswbuf == 0) {
		nswbuf = (nbuf / 2) &~ 1;       /* force even */
		if (nswbuf > 256)
			nswbuf = 256;           /* sanity */
	}

	/*
	 * Allocate space for system data structures.
	 * The first available real memory page is "firstaddr".
	 * The first available kernel virtual page is "v".
	 * Note that these pages were pre-mapped by locore when
	 * the HAT/IPT table was initialized, so no remapping need
	 * be done here.
	 */
	v = (caddr_t)(SYSBASE | (firstaddr * NBPG));


#define valloc(name, type, num) \
	  (name) = (type *)(v); (v) = (caddr_t)((name)+(num))
#define valloclim(name, type, num, lim) \
	  (name) = (type *)(v); (v) = (caddr_t)((lim) = ((name)+(num)))

	if (ishole(firstaddr))
		panic("hit hole in memory");
	valloc(buf, struct buf, nbuf);
	valloc(swbuf, struct buf, nswbuf);
	valloclim(inode, struct inode, ninode, inodeNINODE);
	valloclim(file, struct file, nfile, fileNFILE);
	valloclim(proc, struct proc, nproc, procNPROC);
	valloclim(text, struct text, ntext, textNTEXT);
#ifdef	VICE
	valloclim(rmt_wd, struct rmt_wd, nrmt_wd, rmt_wdNRMT_WD);
#endif
	valloc(cfree, struct cblock, nclist);
	valloc(callout, struct callout, ncallout);
	valloc(swapmap, struct map, nswapmap = nproc * 2);
	valloc(argmap, struct map, ARGMAPSIZE);
	valloc(kernelmap, struct map, nproc);
	valloc(mbmap, struct map, nmbclusters/4);
#ifndef VFS
	valloc(namecache, struct namecache, nchsize);
#else !VFS
	valloc(ncache, struct ncache, ncsize);
#endif !VFS
#ifdef QUOTA
#ifndef VFS
	valloclim(quota, struct quota, nquota, quotaNQUOTA);
#endif !VFS
	valloclim(dquot, struct dquot, ndquot, dquotNDQUOT);
#endif
	/*
	 * Now allocate space for core map.
	 * Allow space for all of physical memory minus the amount
	 * dedicated to the system. The amount of physical memory
	 * dedicated to the system is everything below the real
	 * page corresponding to "v" at this point minus everything
	 * above "maxmem", i.e. the pages previously allocated for
	 * the HAT/IPT table, the buffers, and the console message
	 * buffer. Some trickiness here because we also want to put
	 * the core map in system memory!
	 */
	ncmap = (maxmem * NBPG - ((int)v &~ SYSBASE)) /
			(NBPG*CLSIZE + sizeof(struct cmap));
	ncmap += 2; /* SLOP -- Seems to be necessary, can't hurt */
	valloclim(cmap, struct cmap, ncmap, ecmap);
	unixsize = btoc((int)(ecmap+1) &~ SYSBASE);
	if (unixsize >= maxmem - 8*UPAGES)
		panic("no memory");

	if (ishole(unixsize))
		panic("valloc: hit hole in memory");

	/*
	 * Initialize memory allocator and swap
	 * and user page table maps.
	 *
	 * THE USER PAGE TABLE MAP IS CALLED "kernelmap"
	 * WHICH IS A VERY UNDESCRIPTIVE AND INCONSISTENT NAME.
	 *
	 * [I love this comment which is the only reason I
	 *  don't rename the stupid variable]
	 */
	meminit(unixsize, maxmem);
	rminit(kernelmap, (long)USRPTSIZE, (long)1, "usrpt", nproc);
	rminit(mbmap, (long)((nmbclusters - 1) * CLSIZE), (long)CLSIZE,
				"mbclusters", nmbclusters/4);

	/*
	 * Print some memory statistics.
	 */
#ifdef DEBUG
	printf("Memory allocation:  ");
	printf("%dK (0x%x)\tKernel static text/data/bss\n\r",
				ctob(firstaddr)/1024, ctob(firstaddr));
	i = ctob(bufpages);
	printf("                    ");
	if (i < 102400) printf(" ");
	printf("%dK (0x%x)\tBuffer cache (%d buffers)\n\r",
				i/1024, i, nbuf);
	i = ctob((unixsize - firstaddr) + (endmem - maxmem) - bufpages);
	printf("                    ");
	if (i < 102400) printf(" ");
	printf("%dK (0x%x)\tOther dynamically mapped data areas\n\r",
				i/1024, i);
#else DEBUG
	printf("Using %d buffers containing %dK bytes\n",
				nbuf, ctob(bufpages)/1024);
#endif DEBUG
	printf("Memory summary: total %dK (0x%x), ",
				ctob(physmem)/1024, ctob(physmem));
	printf("available %dK (0x%x)\n",
				ctob(freemem)/1024, ctob(freemem));
	
#ifdef DEBUG
	if (holelength) {
		printf("Memory hole: from %dK (0x%x) ",
			ctob(holestart)/1024, ctob(holestart));
		printf("to %dK (0x%x)\n",
			ctob(holestart+holelength)/1024, ctob(holestart+holelength));
	}
#endif
	/*
	 * From now on, maxmem is the max FREE mem
	 */
	maxmem = freemem;

	/*
	 * Initialize callouts
	 */
	callfree = callout;
	for (i = 1; i < ncallout; i++)
		callout[i-1].c_next = &callout[i];

#ifdef VFS
	/*
	 *	initialize kernel memory allocator
	 */
	kmem_init();
#endif VFS

	/*
	 * Configure the system.
	 */
	configure();

       /* enable interrupts */
       spl0();
       DISPLAY(LED_BLANK);	/* blank lights */

	{
	/*
	 * set up switches for init
	 */
		extern char howtoarg[];
		register char *p = howtoarg;

		*p++ = '-';		/* always put out - */
		if (boothowto & RB_ASKNAME)
			*p++ = 'a';
		if (boothowto & RB_SINGLE)
			*p++ = 's';
		*p++ = 0;
	}
}

#ifdef PGINPROF
/*
 * Return the difference (in microseconds)
 * between the  current time and a previous
 * time as represented  by the arguments.
 * If there is a pending clock interrupt
 * which has not been serviced due to high
 * ipl, return error code.
 */
vmtime(otime, olbolt, oicr)
register int otime, olbolt, oicr;
{
	printf("vmtime called!\n");
	/*     if (mfpr(ICCS)&ICCS_INT)
		       return(-1);
	       else
		       return(((time.tv_sec-otime)*60 + lbolt-olbolt)*16667 + mfpr(ICR)-oicr);
	*/
}
#endif

#define RTFL_MASK	0xffffff00	/* mask off data byte of BALA */
#define RTFL_MAGIC	0x60f08a00	/* cas r0,r15,r0 ; bala fpglue */

/*
 * Send an interrupt to process.
 *
 * Stack is set up to allow sigcode stored
 * in u. to call routine, followed by chmk
 * to sigcleanup routine below.  After sigcleanup
 * resets the signal mask and the stack, it
 * restores the registers and does a lps to return
 * to user code.
 */

sendsig(p, sig, mask)
int (*p)(), sig, mask;
{
	register int *regs,*rp1,*rp2;
	register struct sigframe *fp;
	register struct sigcontext *scp;
	int oonstack;

	DEBUGF(sydebug&SHOW_SIGNAL,
		printf("sendsig, p=%x,sig=%x,mask=%x\n",p,sig,mask));
	regs = u.u_ar0;
	oonstack = u.u_onstack;

	/*
	 * Push a stack frame for this signal
	 */
	if (!oonstack && (u.u_sigonstack & sigmask(sig))) {
		/* wasn't on onstack, and wants to be */
		fp = (struct sigframe *)u.u_sigsp - 1;
		u.u_onstack = 1;
	}
	else
		/* was on onstack, or doesn't want to be */
#ifdef DUALCALL
		fp = (struct sigframe *)
			(regs[SP] + (u.u_calltype?FRM_PROTECT:0)) - 1;
#else
		fp = (struct sigframe *)
			(regs[SP] + FRM_PROTECT) - 1;
#endif DUALCALL

	scp = &fp->sf_sc;
	/*
	 * Make sure the stack will hold the new context
	 */
	if (!u.u_onstack && (unsigned)fp < USRSTACK - ctob(u.u_ssize))
		GROWSP((unsigned)fp);

	/*
	 * Make sure we can access the new signal frame
	 */
	if (!useracc((caddr_t)fp,sizeof(struct sigframe),B_WRITE)) {
		/* can't get there! */
		/* process has trashed its stack; give it an illegal */
		/* instruction to halt it in its tracks */
		u.u_signal[SIGILL] = SIG_DFL;
		sig = sigmask(SIGILL);
		u.u_procp->p_sigignore &= ~sig;
		u.u_procp->p_sigcatch &= ~sig;
		u.u_procp->p_sigmask &= ~sig;
		psignal(u.u_procp, SIGILL);
		return;
	}

	/*
	 * Set up the sigcontext to be passed to p()
	 */
	scp->sc_onstack = oonstack;
	scp->sc_mask = mask;
	scp->sc_icscs = regs[ICSCS];
	scp->sc_floatsave = 0;

	/*
	 * Save the current registers
	 */
	rp1 = &regs[MQ];
	rp2 = &(scp->sc_regs[MQ]);
	while (rp1 >= regs)
		*rp2-- = *rp1--;

	/*
	 * Set up registers to call p()
	 */
	regs[R2] = fp->sf_signum = sig; /* 1st parameter: sf_signum */
#ifdef NFL
#include "../machine/fp.h"
	if (sig == SIGFPE) {
	    if (float_sendsig(fp)) {	/* Call floating point code to send */
		scp->sc_flags |= SC_FLOATSAVE;
		fp->sf_sc.sc_floatsave = (char *) &(fp->sf_floatsave);
	    }
	}
#endif NFL
#ifdef SC_RTFL
	/*
	 * The RTFL has one case that we have to check for here.
	 * RTFL entry code is (aligned on a fullword boundary):
	 *	cas	r0,r15,r0
	 *	bala	fpglue
	 * if we take a signal after the case, but before the bala, and if
	 * the signal handler then reexecutes the generated code, then when
	 * we return from the handler the IAR will be partway thru the generated
	 * code and we are in trouble.
	 * This code checks to see if this might be happening, and sets a flag
	 * that sigcleanup will check to see if the RTFL magic sequence has been
	 * changed. If it has then we back up the IAR to point to the start of
	 * the code and continue execution. For efficiency we only look into
	 * the user address space if the IAR is non-aligned and if R0 == R15
	 * (after all we should have just executed a cas r0,r15,r0).
	 */
	if ((regs[IAR]&2) && regs[R0] == regs[R15] &&
			(fuword(regs[IAR]-2)&RTFL_MASK) == RTFL_MAGIC) {
		scp->sc_saveiar = regs[IAR];	/* save the IAR */
		scp->sc_flags |= SC_RTFL;	/* possible RTFL case */
		DEBUGF(sydebug&SHOW_SIGNAL, printf("sendsig: IAR=%x possible RTFL!\n",regs[IAR]));
	}
#endif SC_RTFL
#ifdef ROMPC
	/*
	 * copy exception information into sigframe so that packets
	 * can be reissued after the signal is complete 
	 * note that the exception information is taken from our 
	 * stack - signals sent from another process won't save
	 * exception information as there won't be any on our 
	 * stack.
	 */
#ifdef SGP
#ifdef MOD135
	if (cpu_model == CPU_ROMPC || cpu_model == CPU_MOD135)
#else
	if (cpu_model == CPU_ROMPC)
#endif MOD135
#endif SGP
	if (scp->sc_regs[ECR_COUNT] = regs[ECR_COUNT]) {
		bcopy((caddr_t)&regs[EX1_CTL],
			(caddr_t) &scp->sc_regs[EX1_CTL],
			regs[ECR_COUNT] * sizeof (struct ex_packet));
		regs[ECR_COUNT] = 0;	/* forget about exception for now */
		scp->sc_flags |= SC_EXCEPTION;
	}
#endif ROMPC
	if (sig == SIGILL || sig == SIGFPE) {
		regs[R3] = fp->sf_code = u.u_code; /* 2nd parameter: sf_code */
		u.u_code = 0;
	}
	else
		regs[R3] = fp->sf_code = 0; /* 2nd parameter: sf_code */
	regs[R4] = (int)(fp->sf_scp = &(fp->sf_sc));/* 3rd parameter: sf_scp */
	regs[R15] = (int)u.u_pcb.pcb_sigc;  /* return addr:  svc 139 */
#ifdef DUALCALL
	if (u.u_calltype)
#endif DUALCALL
	{
	    regs[R0] = (int)p;
	    regs[IAR] = fuword((caddr_t)p);
	}
#ifdef DUALCALL
	else
	    regs[IAR] = (int)p;                 /* addr of signal handler */
#endif DUALCALL
	regs[SP] = (int)fp;                 /* push signal context */

	/*
	 * "Return" to the handler
	 */
	return;
}

/*
 * Routine to cleanup state after a signal
 * has been taken.  Reset signal mask and
 * stack state from context left by sendsig (above).
 * Then restore saved registers and simulate return from interrupt
 * (lps).
 */
sigcleanup(scp)
register struct sigcontext *scp;
{
	register int *regs, *rp1, *rp2;

	regs = u.u_ar0;
	DEBUGF(sydebug&SHOW_SIGNAL, printf("sigcleanup regs=%x scp=%x\n",regs,scp));

	if (useracc((caddr_t)scp, sizeof (*scp), B_WRITE) == 0)
		return;

	if ((scp->sc_flags&SC_FLOATSAVE) &&
		    useracc((caddr_t)scp->sc_floatsave,
				    sizeof (struct floatsave), B_WRITE) == 0)
		return;
#ifdef SC_RTFL
	/*
	 * check to see if we have a RTFL case and if we need to do 
	 * RTFL fixup.
	 */
	if ((scp->sc_flags&SC_RTFL) && scp->sc_iar == scp->sc_saveiar &&
			(fuword(scp->sc_saveiar-2) & RTFL_MASK) != RTFL_MAGIC) {
		printf("RTFL JACKPOT!!!\n");	/* was this worthwhile? */
		scp->sc_iar -= 2;		/* adjust the IAR back to 
						   the beginning of the RTFL
						   block.  */
	}
#endif SC_RTFL
	/*
	 * Restore registers
	 */
	rp1 = &regs[MQ];
	rp2 = &(scp->sc_regs[MQ]);
	while (rp1 >= regs)
		*rp1-- = *rp2--;

#ifdef ROMPC
	/*
	 * copy exception information from sigframe so that packets
	 * will be reissued upon return from syscall and sigcleanup.
	 */
#ifdef SGP
#ifdef MOD135
	if (cpu_model == CPU_ROMPC || cpu_model == CPU_MOD135)
#else
	if (cpu_model == CPU_ROMPC)
#endif MOD135
#endif SGP
	if ((scp->sc_flags&SC_EXCEPTION) && (regs[ECR_COUNT] = scp->sc_regs[ECR_COUNT])) {
		if ((unsigned) regs[ECR_COUNT] > MAX_EXCEPTIONS)
			regs[ECR_COUNT] = MAX_EXCEPTIONS;	/* paranoia */
		DEBUGF(sydebug&SHOW_SIGNAL, printf("sigcleanup: %d exceptions\n",regs[ECR_COUNT]));
		bcopy((caddr_t) &scp->sc_regs[EX1_CTL],
			(caddr_t) &regs[EX1_CTL],
			regs[ECR_COUNT] * sizeof (struct ex_packet));
	}
#endif ROMPC

	/*
	 * Alter registers available to signal handler
	 */
	regs[ICSCS] = scp->sc_icscs | ICSCS_USERSET & ~ICSCS_USERCLR;

	DEBUGF(sydebug&SHOW_SIGNAL, printf("sigcleanup IAR=%x SP=%x ICS_CS=%x\n",
		regs[IAR], regs[SP], regs[ICSCS]));	/* */
	DEBUGF(sydebug&SHOW_SIGREGS, prstate("sigcleanup", 0, 0, regs[IAR], regs[ICSCS],regs));	/* */

	/*
	 * Alter floating point registers 
	 */
	if (scp->sc_flags&SC_FLOATSAVE)
		float_sigcleanup(scp);

	/*
	 * Restore signal values
	 */
	u.u_onstack = scp->sc_onstack & SC_ONSTACK;
	u.u_procp->p_sigmask = scp->sc_mask & ~(sigmask(SIGKILL) |
	    sigmask(SIGCONT) | sigmask(SIGSTOP));
}

#ifdef notdef
dorti()
{
       struct frame frame;
       register int sp;
       register int reg, mask;
       extern int ipcreg[];

       (void) copyin((caddr_t)u.u_ar0[FP], (caddr_t)&frame, sizeof (frame));
       sp = u.u_ar0[FP] + sizeof (frame);
       u.u_ar0[PC] = frame.fr_savpc;
       u.u_ar0[FP] = frame.fr_savfp;
       u.u_ar0[AP] = frame.fr_savap;
       mask = frame.fr_mask;
       for (reg = 0; reg <= 11; reg++) {
	       if (mask&1) {
		       u.u_ar0[ipcreg[reg]] = fuword((caddr_t)sp);
		       sp += 4;
	       }
	       mask >>= 1;
       }
       sp += frame.fr_spa;
       u.u_ar0[PS] = (u.u_ar0[PS] & 0xffff0000) | frame.fr_psw;
       if (frame.fr_s)
	       sp += 4 + 4 * (fuword((caddr_t)sp) & 0xff);
       /* phew, now the rei */
       u.u_ar0[PC] = fuword((caddr_t)sp);
       sp += 4;
       u.u_ar0[PS] = fuword((caddr_t)sp);
       sp += 4;
       u.u_ar0[PS] |= PSL_USERSET;
       u.u_ar0[PS] &= ~PSL_USERCLR;
       u.u_ar0[SP] = (int)sp;
}
#endif

/*
 * Invalidate single all pte's in a cluster
 */
#ifdef DEBUG
tbiscl(v)
unsigned v;
{
	printf("tbiscl(v=%x)\n",v);
}
#endif DEBUG

/*
 * Reboot the system, with various options
 */
int    waittime = -1;

boot(paniced, arghowto)
int paniced, arghowto;
{
       register int howto;             /* r11 == how to boot */
       register int devtype;           /* r10 == major of root dev */
       register int x;

       DEBUGF(svdebug, printf("paniced=%x,arghowto=%x\n", paniced, arghowto));
#ifdef IBMRTPC
        x = * (int *) CSR;		/* clear csr lock */
       * (int *) CSR = x-x;		/* and reset it */
#endif IBMRTPC
       (void) spl1();                  /* allow disk intr */
       howto = arghowto;
       if (howto&RB_SUSPEND) {
#ifdef ATR
		if (config.os_type == DOS_TYPE)
			suspend_screens();	/* save the screens */
		else
#endif ATR
		{	/* not ATR or not possible on ATR */
			u.u_error = EINVAL;
			(void) spl0();
			return;
		}
	}
       if ((howto&RB_NOSYNC)==0 && waittime < 0 && bfreelist[0].b_forw) {
	       extern int updlock;
	       waittime = 0;
	       if  (updlock == 0)
	       		update();
	       printf("syncing disks... ");
	       { register struct buf *bp;
		 int iter, nbusy = 0, lbusy = 0;

		 for (iter = 0; iter < 20; iter++) {
		       nbusy = 0;
		       for (bp = &buf[nbuf]; --bp >= buf; )
			       if ((bp->b_flags & (B_BUSY|B_INVAL)) == B_BUSY)
				       nbusy++;
		       if (nbusy < lbusy)
			       iter = 0;
		       if ((lbusy = nbusy) == 0)
			       break;
		       printf("%d ", nbusy);
		       for (nbusy=100000; nbusy; --nbusy)
		       		;	/* a bit of a delay */
		 }
	       }
	       printf("done\n");
       }
       (void) spl7();                         /* extreme priority */
       devtype = major(rootdev);
       if (howto&RB_HALT) {
#ifdef ATR
	/*
	 * Reset the network devices before going back to DOS to prevent
	 * any stray interrupts killing DOS; we use the "vax" ubareset
	 * routine since it does exactly what we want.
	 */
		printf("resetting network devices\n");
		ifubareset(0);
#endif ATR
		printf("halting (via wait);\n");
		delay(1000);			/* allow message to be read */
		DISPLAY(LED_BLANK);		/* turn out the light */
		for (;;) {
#ifdef ATR
			pc_req(CB_HALT,0,0);	/* tell PC to halt */
#endif ATR
			asmwait();		/* closest thing to a halt */
	       }
#ifdef ATR
       } else if (howto&RB_SUSPEND) {
		suspend();
		return;				/* we can return from suspend! */
#endif ATR
       } else {
	       if (paniced == RB_PANIC) {
			delay(1000);		/* allow message to be read */
			dumpsys();              /* dump to swap area */
	       }
	       delay(1000);			/* allow messages to be read */
	       for (;;)
			_reboot(howto,devtype);
	}
}


int    dumpmag = 0x8fca0101;   /* magic number for savecore */
int    dumpsize = 0;           /* also for savecore */
/*
 * Doadump comes here after turning off memory management and
 * getting on the dump stack, when called by the system attention code
 * or more directly from above during 'boot' when called from 'panic'. 
 */
dumpsys()
{

       dumpsave();		/* save important MM stuff */
       dumpsize = endmem;	/* dump includes the hole */
       printf("\ndumping to dev %x, offset %d\n", dumpdev, dumplo);
       printf("dump ");
       switch ((*bdevsw[major(dumpdev)].d_dump)(dumpdev)) {

	case ENODEV:
		printf("driver can't dump yet\n");
		break;

       case ENXIO:
               printf("device bad\n");
               break;

       case EFAULT:
               printf("device not ready\n");
               break;

       case EINVAL:
               printf("area improper\n");
               break;

       case EIO:
               printf("i/o error");
               break;

       default:
		printf("failed\n");
		break;
	case 0:
               printf("succeeded");
               break;
       }
}

/*
 * I'm not sure what is machine independent about this one XXX
 */
physstrat(bp, strat, prio)
struct buf *bp;
int (*strat)(), prio;
{
       int s;

       (*strat)(bp);
       /* pageout daemon doesn't wait for pushed pages */
       if (bp->b_flags & B_DIRTY)
	       return;
       s = spl6();
       while ((bp->b_flags & B_DONE) == 0)
	       sleep((caddr_t)bp, prio);
       splx(s);
}



/*
 * This is where the "soft network" interrupt comes to. The
 * hardware interrupt routine has pulled the packet off the
 * interface and now wants us to run (at lower priority) the
 * protocol family specific routine to munch the packet.
 */
softnet()
{
#ifdef INET
#define LOCORE /* *sigh* */
#include "../net/netisr.h"
#undef LOCORE /* unsigh */
	extern int netisr;
	if (netisr & (1<<NETISR_RAW)) {
		netisr &= ~(1<<NETISR_RAW);
		rawintr();
	}
	if (netisr & (1<<NETISR_IP)) {
		netisr &= ~(1<<NETISR_IP);
		ipintr();
	}
	return(0);
#else INET
	return (1);
#endif INET
}

/*
 * Debugger -- go enter the debugger, if we have one
 * We return when done debugging (or if there is no debugger)
 */

/*
 * debug_flag determines what action we take upon a call to debugger
 * if debug_flag > 0 then we invoke the debugger if there has been
 * console input within that many seconds. 
 * if debug_flag == 0 then we always invoke the debugger
 * if debug_flag < 0 then we print a message, wait for a while
 * and then return.
 */
int debug_flag = 60;
Debugger(s)
char *s;
{
	/*      extern char etext, end; /* */
	register int n = debug_flag;
	extern unsigned long cons_sec;

	/*
	 * Check validity of s before we try to use it
	 */
	printf("Debugger called from %s.\n",
		( ((u_int) s > (u_int) &etext) &&
		  ((u_int) s < (u_int) &end) && *s)? s : "someplace");
#ifdef RDB
	if (n == 0 || cons_sec+n >= time.tv_sec) {
		printf("Type \"go iar+2\" to continue execution.\n");
		asmtgte();	/* asm(" tgte r1,r1 ");  */
	}
	else {
		if (n < 0) 
			n = -n;
		printf("Press <CTRL><ALT><SCROLL-LOCK> to enter debugger\n");
		delay(n << 10);
	}
#else
	printf("(But we weren't compiled with RDB!  Sorry.)\n");
#endif RDB
}

/*
 * Clear registers on exec
 */
int
setregs(entry,name)
	unsigned entry;
	char *name;
{
	register int i, j;

	if (u.u_procp->p_sig&(1<<(SIGKILL-1)))
		return;		/* SIGKILL pending - just return - text might not have been allocated (swkill done) */
#ifdef notdef
	/* should pass args to init on the stack */
	for (rp = &u.u_ar0[0]; rp < &u.u_ar0[16];)
		*rp++ = 0;
#endif
	i = u.u_ar0[IAR] = entry;
	fp_mach_init();
#if (1)		/* was DUALCALL */
	/* Old calling sequence crt0 begins with

		start:	j   next
			.ascii "<start>"
	   and expects kframe (struct argument) to be on the stack.

	   New calling sequence crt0 begins with

		start:  j   .start
			.short 1	# version number, eventually
			.long  magicno  # magic number -- to be determined
			.long  _start   # to let execve load data ptr in r0
			.globl __fpfpr
			.long  __fpfpr  # location of software fp status
			.ascii "<start>"
			.start:
	   and expects the first four words of kframe to be in r2-r5,
	   which it will store on the stack. 
	*/
	j = fuiword((caddr_t) i) & 0xffff;	/* .short 1  or "<s" */
	if (j < 256) { 	/* Must be NCS */
	    u.u_calltype = j;
	    u.u_r.r_val2 = fuiword((caddr_t) i+NBPW*2);/* val1->R0 in trap.c */
#ifdef notdef
	    u.something = fuiword((caddr_t) i+NBPW*3) /* record fp status addr*/
#endif notdef
		/* Copy first 4 words of kframe struct into user's r2-r5, 
		   and bump sp past them.
		 */
	    for (i=R2; i<R6; i++, u.u_ar0[SP] += NBPW)
		u.u_ar0[i] = fuword((caddr_t) u.u_ar0[SP]); 
	    u.u_r.r_val1 = u.u_ar0[R2];		/* val2 -> R2 in trap.c */
	}
	else u.u_calltype = 0;			/* OCS */ 
#ifndef DUALCALL
	if (u.u_calltype == 0)
		uprintf("%s: old calling sequence\n",name);
#endif DUALCALL
#endif (1)
	/*
	 * restore ccr to default state 
	 * by clearing all bits not on in 
	 * default case.
	 */
	set_ccr(0x80000000 | (int) ccr_default);
	/* 
	 * restore consdev by clearings bits for
	 * all possible console devices
	 */
	set_consdev(0x80000000 | (int) 0);
	/*
	 * upon exec release the current register set (as is done
	 * upon exit.
	 */
	float_exit(u.u_procp);		/* release register set */
}


#ifdef KCALL
/*
 * kcall - call given address in kernel mode with the given parameters.
 */
kcall()
{
	register struct a {
		int	(*fn)();	/* function to call */
		int	arg1;	/* and some arguments */
		int	arg2;
		int	arg3;
	} *a = (struct a *) u.u_ap;

	if (suser())
		u.u_r.r_val1 = (*(a->fn))(a->arg1,a->arg2,a->arg3);
}
#endif KCALL

#ifdef SYSCALLTRACE
/*
 * syscalltrace - turn on/off system call tracing 
 * just for fun return the previous value.
 */
syscalltrace()
{
	register struct a {
		int	flag;	/* flag==0 or != 0 */
	} *a = (struct a *) u.u_ap;

	u.u_r.r_val1 = (u.u_procp->p_flag & STRACE) != 0;

	if (a->flag)
		u.u_procp->p_flag |= STRACE;
	else
		u.u_procp->p_flag &= ~STRACE;
}
#endif SYSCALLTRACE

/*
 * set/clear bits in the ccr for this process
 * if top bit in value is on then we clear the given
 * bits otherwise set them.
 */
set_ccr(value) register int value;
{
#ifdef IBMRTPC
if (value < 0) {
	u.u_pcb.pcb_ccr &= value;
} else {
	u.u_pcb.pcb_ccr |= value;
}
* (char *) CCR = u.u_pcb.pcb_ccr;
#endif IBMRTPC
#ifdef ATR
/*
 * pcb_io performs the same function for ATR as pcb_ccr does in the RT
 * namely it controls user access to the I/O space. It contains the value
 * of the transaction id. Currently TID=0 means access, and TID= any thing
 * else means no access. In the future, TID may be used to control access
 * between multiple display devices. (display 1 may have TID=1, display 2 may
 * have TID=2, etc.)
 */
if (value < 0) {
	u.u_pcb.pcb_io = MMU_IO_DISABLE;
} else {
	u.u_pcb.pcb_io = MMU_IO_ENABLE;
}
iow(MMU_TID_ADDR,u.u_pcb.pcb_io);
#endif
}

/*
 * set/clear bits in the consdev (console device flags) for this process
 * if top bit in value is on then we clear the given
 * bits otherwise set them.
 */
set_consdev(value) register int value;
{

if (value < 0)
	u.u_pcb.pcb_consdev &= value;
else
	u.u_pcb.pcb_consdev |= value;
}

/* 
 * return the value in the console device flags for this process.
 */
get_consdev()
{
	return(u.u_pcb.pcb_consdev);
}


#define DELAY_COUNT 500
int delay_count = DELAY_COUNT;

/* 
 * give 'n' milliseconds of real-time delay.
 */

delay(n)
	register int n;
{
	register int i;
	extern char delay_addr;

	while (--n >= 0)
		for (i = delay_count; --i >= 0;)
			* (char *) DELAY_ADDR = 0xFF;
}

/*
 * Return the best possible estimate of the time in the timeval
 * to which tvp points.  We do this by reading the interval count
 * register to determine the time remaining to the next clock tick.
 * We must compensate for wraparound which is not yet reflected in the time
 * (which happens when the ICR hits 0 and wraps after the splhigh(),
 * but before the mfpr(ICR)).  Also check that this time is no less than
 * any previously-reported time, which could happen around the time
 * of a clock adjustment.  Just for fun, we guarantee that the time
 * will be greater than the value obtained by a previous call.
 */
microtime(tvp)
	register struct timeval *tvp;
{
	int s = splhigh();
	static struct timeval lasttime;
	register long t;
	extern unsigned timer_base;

	*tvp = time;
	t =  (timer_base - mfsr(SCR_TIMER)) * (MICROSECSEC / CPU_CLOCK_HZ);
#ifdef notdef
	if (t < -tick / 2 && (mfpr(ICCS) & ICCS_INT))
		t += tick;
#endif
	tvp->tv_usec += t;
	if (tvp->tv_usec > 1000000) {
		tvp->tv_sec++;
		tvp->tv_usec -= 1000000;
	}
	if (tvp->tv_sec == lasttime.tv_sec &&
	    tvp->tv_usec <= lasttime.tv_usec &&
	    (tvp->tv_usec = lasttime.tv_usec + 1) > 1000000) {
		tvp->tv_sec++;
		tvp->tv_usec -= 1000000;
	}
	lasttime = *tvp;
	splx(s);
}


/*
 * adjust the value of the delay_count variable so that it gives
 * as close to 1 millisecond delay as we can expect.
 * we do this by doing a nominal 1second delay and adjusting
 * the delay count by the resulting change in the time variable.
 */
#define ADJUST_TIME	1000	/* number of millseconds to delay */
delay_adjust()
{
	struct timeval tv = time;	/* start time */
	long eltime;			/* difference in usec */
	long new_count;

	delay(ADJUST_TIME);		/* nominal 1 second delay */
	eltime = (time.tv_sec-tv.tv_sec) * 1000 + (time.tv_usec-tv.tv_usec)/1000;	/* actual time taken by delay(ADJUST_TIME) */
	if (eltime <= 0)
		printf("oops, clock not running (%d)\n",eltime);
	else {
		new_count = (delay_count * ADJUST_TIME) / eltime;
		DEBUGF(1, printf("adjust delay_count from %d to %d\n",delay_count,new_count));
		delay_count = new_count;
	}
}

/* 
 * adjust the delays according to the CPU type
 * a finer adjustment will be made later but we need a close 
 * approximation for the probe routines.
 */
delay_preadjust()
{
#ifdef ATR
	delay_count = 500;
#else
	if (cpu_model == CPU_ROMPC)
		delay_count = 600;
#ifdef MOD135
	else if (cpu_model == CPU_MOD135)
		delay_count = 800;
#endif MOD135
	else
		delay_count = 400;
#endif ATR
}


struct post *
get_post(io_addr)	/* should be moved to machdep.c */
	register caddr_t io_addr;
{
	register struct post *pp;
	
	for (pp = &POST_CB.posts[0]; pp < &POST_CB.posts[NPOSTS]; pp++) {
		if (pp->primary == (u_short)io_addr)
			return (pp);
	}
	return (NULL);
}

/*
 * System call to cleanup state after a signal
 * has been taken.  Reset signal mask and
 * stack state from context left by sendsig (above).
 * Return to previous pc and psl as specified by
 * context left by sendsig. Check carefully to
 * make sure that the user has not modified the
 * psl to gain improper priviledges or to cause
 * a machine fault.
 */
sigreturn()
{
	struct a {
		struct sigcontext *sigcntxp;
	};
	register struct sigcontext *scp;

	scp = ((struct a *)(u.u_ap))->sigcntxp;
	sigcleanup(scp);
	u.u_eosys = JUSTRETURN;
}

baddev()
{
	panic("baddev");
}
