File:  [Power 6/32 Unix Tahoe 4.2BSD] / cci / sys / tahoe / machdep.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs
Sun Jul 28 12:30:04 2019 UTC (7 years ago) by root
Branches: bsd, MAIN
CVS tags: v121, HEAD
Power 6/32 Unix version 1.21

/*	machdep.c	6.2	83/10/02	*/

#include "../machine/reg.h"
#include "../machine/pte.h"
#include "../machine/psl.h"

#include "../h/param.h"
#include "../h/systm.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/kernel.h"
#include "../h/map.h"
#include "../h/vm.h"
#include "../h/proc.h"
#include "../h/buf.h"
#include "../h/reboot.h"
#include "../h/conf.h"
#include "../h/inode.h"
#include "../h/file.h"
#include "../h/text.h"
#include "../h/clist.h"
#include "../h/callout.h"
#include "../h/cmap.h"
#include "../h/mbuf.h"
#include "../h/msgbuf.h"
#include "../h/quota.h"

#ifdef SYS5
#include "../h/msg.h"
#endif SYS5

#include "../machine/mem.h"
#include "../machine/mtpr.h"
#include "../machine/cp.h"
#include "../vba/vbavar.h"

#ifdef AUDITTRAIL
#include "../h/audit.h"
#endif AUDITTRAIL

int	icode[] =
/*		pushab	argp		*/
/*		pushab	file		*/
/*		pushl	$2		*/
/*		movab	(sp),fp		*/
/*		kcall	$exec		*/
/*	here:	brb	here		*/
/*	.file:	.ascii	"/etc/"		*/
/*	args:	.ascii	"init\0"	*/
/*		.align	2		*/
/*	argp:	.long	args		*/
/*		.long	0		*/
{
	0xf9af19f9,
	0xaf09dd02,
	0xe96e5dcf,
	0x0b11fe2f,
	0x6574632f,
	0x696e6974,
	0x00000000,
	0x00000014,
	0x00000000,
};
int	szicode = sizeof(icode);
 
/*
 * Declare these as initialized data so we can patch them.
 */
int	nbuf = 0;
int	nswbuf = 0;
int	bufpages = 0;

/*
 * Machine-dependent startup code
 */
startup(firstaddr)
	int firstaddr;
{
	register int unixsize;
	register unsigned i;
	register struct pte *pte;
	register int mapaddr, j;
	register caddr_t v;
	register int maxbufs, base, residual;
	extern char etext;

	/*
	 * Initialize error message buffer (at end of core).
	 */
	maxmem -= btoc(sizeof (struct msgbuf));
	pte = msgbufmap;
	for (i = 0; i < btoc(sizeof (struct msgbuf)); i++)
		*(int *)pte++ = PG_V | PG_KW | (maxmem + i);
	mtpr(1,TBIA);

	/*
	 * Good {morning,afternoon,evening,night}.
	 */
	printf(version);
	printf("real mem  = %d\n", ctob(maxmem));
	
	/*
	 * Determine how many buffers to allocate.
	 * Use 10% of memory, with min of 16.
	 * We allocate 1/2 as many swap buffer headers as file i/o buffers.
	 */
	maxbufs = ((SYSPTSIZE * NBPG) - (5 * (int)(&etext - 0xc0000000))) /
	    MAXBSIZE;
	if (bufpages == 0)
		bufpages = (physmem * NBPG) / 10 / CLBYTES;
	if (nbuf == 0) {
		nbuf = bufpages / 2;
		if (nbuf < 16)
			nbuf = 16;
		if (nbuf > maxbufs)
			nbuf = maxbufs;
	}
	if (bufpages > nbuf * (MAXBSIZE / CLBYTES))
		bufpages = nbuf * (MAXBSIZE / CLBYTES);
	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 address is in "firstaddr".
	 * As pages of memory are allocated, "firstaddr" is incremented.
	 * The first available kernel virtual address is in "v".
	 * As pages of kernel virtual memory are allocated, "v" is incremented.
	 * An index into the kernel page table corresponding to the
	 * virtual memory address maintained in "v" is kept in "mapaddr".
	 */
	mapaddr = firstaddr;
	v = (caddr_t)(0xc0000000 | (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)))
	valloc(buffers, char, MAXBSIZE * nbuf);
	base = bufpages / nbuf;
	residual = bufpages % nbuf;
	for (i = 0; i < residual; i++) {
		for (j = 0; j < (base + 1) * CLSIZE; j++) {
			*(int *)(&Sysmap[mapaddr+j]) = PG_V | PG_KW | firstaddr;
			clearseg((unsigned)firstaddr);
			firstaddr++;
		}
		mapaddr += MAXBSIZE / NBPG;
	}
	for (i = residual; i < nbuf; i++) {
		for (j = 0; j < base * CLSIZE; j++) {
			*(int *)(&Sysmap[mapaddr+j]) = PG_V | PG_KW | firstaddr;
			clearseg((unsigned)firstaddr);
			firstaddr++;
		}
		mapaddr += MAXBSIZE / NBPG;
	}
	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 SYS5
	valloclim(shmem, struct shmid_ds, nshmem, shmemNSHMEM);
#endif SYS5
	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);
#ifdef SYS5
	valloc(msgmap, struct map, MSGMAP);
#endif SYS5
#ifdef QUOTA
	valloclim(quota, struct quota, nquota, quotaNQUOTA);
	valloclim(dquot, struct dquot, ndquot, dquotNDQUOT);
#endif

#ifdef AUDITTRAIL
	valloc(audbuf, struct audbuf, naudbuf);
#endif AUDITTRAIL
	/*
	 * Now allocate space for core map
	 * Allow space for all of phsical memory minus the amount 
	 * dedicated to the system. The amount of physical memory
	 * dedicated to the system is the total virtual memory of
	 * the system minus the space in the buffers which is not
	 * allocated real memory.
	 */
	ncmap = (physmem*NBPG - ((int)v &~ 0xc0000000) +
		(nbuf * MAXBSIZE - bufpages * CLBYTES)) /
		    (NBPG*CLSIZE + sizeof (struct cmap));
	valloclim(cmap, struct cmap, ncmap, ecmap);
	if ((((int)(ecmap+1))&~0xc0000000) > SYSPTSIZE*NBPG)
		panic("sys pt too small");

	/*
	 * Clear allocated space, and make r/w entries
	 * for the space in the kernel map.
	 */
	unixsize = btoc((int)(ecmap+1) &~ 0xc0000000);
	for (i = mapaddr; i < unixsize; i++) {
		*(int *)(&Sysmap[i]) = PG_V | PG_KW | firstaddr;
		clearseg((unsigned)firstaddr);
		firstaddr++;
	}
	if (firstaddr >= physmem - 8*UPAGES)
		panic("no memory");
	mtpr(1,TBIA);

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

	/*
	 * 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.
	 */
	meminit(firstaddr, maxmem);
	maxmem = freemem;
	printf("avail mem = %d\n", ctob(maxmem));
	printf("using %d buffers containing %d bytes of memory\n",
		nbuf, bufpages * CLBYTES);
	rminit(kernelmap, (long)USRPTSIZE, (long)1,
	    "usrpt", nproc);
	rminit(mbmap, (long)((nmbclusters - 1) * CLSIZE), (long)CLSIZE,
	    "mbclusters", nmbclusters/4);
#ifdef SYS5
	rminit(msgmap, (long)MSGSEG, (long)1, "msgmap", MSGMAP);
#endif SYS5
	intenable = 1;		/* Enable interrupts from now on */
	/*
	 * Configure the system.
	 */
	configure();
}

#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;
{
	return(((time.tv_sec-otime)*60 + lbolt-olbolt)*16667);
}
#endif

/*
 * 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
 * returns to user who then unwinds with the
 * rei at the bottom of sigcode.
 */
sendsig(p, sig, sigmask)
	int (*p)(), sig, sigmask;
{
	register struct sigcontext *scp;	/* know to be r12 */
	register int *regs;
	register struct sigframe {
		int	sf_signum;
		int	sf_code;
		struct	sigcontext *sf_scp;
		int	(*sf_handler)();
		int	r1;
		int 	r0;
		struct	sigcontext *sf_scpcopy;
	} *fp;					/* known to be r10 */
	int oonstack;

	regs = u.u_ar0;
	oonstack = u.u_onstack;
	scp = (struct sigcontext *)regs[SP] - 1;
#define	mask(s)	(1<<((s)-1))
	if (!u.u_onstack && (u.u_sigonstack & mask(sig))) {
		fp = (struct sigframe *)u.u_sigsp - 1;
		u.u_onstack = 1;
	} else
		fp = (struct sigframe *)scp - 1;
	/*
	 * Must build signal handler context on stack to be returned to
	 * so that rei instruction in sigcode will pop ps and pc
	 * off correct stack.  The remainder of the signal state
	 * used in calling the handler must be placed on the stack
	 * on which the handler is to operate so that the calls
	 * in sigcode will save the registers and such correctly.
	 */
	if (!oonstack && (int)fp <= USRSTACK - ctob(u.u_ssize)) 
		grow((unsigned)fp);
	;
#ifndef lint
	asm("probew $1,(r10),$1");
	asm("jeql bad");
	asm("probew $1,7*4-1(r10),$1");
	asm("jeql bad");
#else
	if (useracc((caddr_t)fp, sizeof (struct sigframe), 1))
		goto bad;
#endif
	if (!u.u_onstack && (int)scp <= USRSTACK - ctob(u.u_ssize))
		grow((unsigned)scp);
	;			/* Avoid asm() label botch */
#ifndef lint
	asm("probew $1,(r12),$1");
	asm("beql bad");
	asm("probew $1,5*4-1(r12),$1");
	asm("beql bad");
#else
	if (useracc((caddr_t)scp, sizeof (struct sigcontext), 1))
		goto bad;
#endif
	fp->sf_signum = sig;
	if (sig == SIGILL || sig == SIGFPE) {
		fp->sf_code = u.u_code;
		u.u_code = 0;
	} else
		fp->sf_code = 0;
	fp->sf_scp = scp;
	fp->sf_handler = p;
	fp->r1 = regs[R1];	/* These are not saved by the C compiler */
	fp->r0 = regs[R0];
	/*
	 * Duplicate the pointer to the sigcontext structure.
	 * This one doesn't get popped by the ret, and is used 
	 * by sigcleanup to reset the signal state on inward return.
	 */
	fp->sf_scpcopy = scp;
	/* sigcontext goes on previous stack */
	scp->sc_onstack = oonstack;
	scp->sc_mask = sigmask;
	/* setup rei */
	scp->sc_sp = (int)&scp->sc_pc;
	scp->sc_pc = regs[PC];
	scp->sc_ps = regs[PS];
	regs[SP] = (int)fp;
	regs[PC] = (int)u.u_pcb.pcb_sigc;
	return;

asm("bad:");
bad:
	/*
	 * Process has trashed its stack; give it an illegal
	 * instruction to halt it in its tracks.
	 */
	u.u_signal[SIGILL] = SIG_DFL;
	sig = mask(SIGILL);
	u.u_procp->p_sigignore &= ~sig;
	u.u_procp->p_sigcatch &= ~sig;
	u.u_procp->p_sigmask &= ~sig;
	psignal(u.u_procp, SIGILL);
}

/*
 * Routine to cleanup state after a signal
 * has been taken.  Reset signal mask and
 * stack state from context left by sendsig (above).
 * Pop these values in preparation for rei which
 * follows return from this routine.
 */
sigcleanup()
{
	register struct sigcontext *scp;	/* known as R12 */

	scp = (struct sigcontext *)fuword((caddr_t)u.u_ar0[SP]);
	if ((int)scp == -1)
		return;
#ifndef lint
	;			/* Avoid asm() label botch */
	/* only probe 12 here because that's all we need */
	asm("prober $1,(r12),$1");
	asm("bnequ 1f; ret; 1:");
	asm("prober $1,11(r12),$1");
	asm("bnequ 2f; ret; 2:");
#else
	if (useracc((caddr_t)scp, sizeof (*scp), 0))
		return;
#endif
	u.u_onstack = scp->sc_onstack & 01;
	u.u_procp->p_sigmask =
	    scp->sc_mask &~ (mask(SIGKILL)|mask(SIGCONT)|mask(SIGSTOP));
	u.u_ar0[SP] = scp->sc_sp;
}
#undef mask

int	waittime = -1;

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

#ifdef lint
	howto = 0; devtype = 0;
	printf("howto %d, devtype %d\n", arghowto, devtype);
#endif
	if (paniced == RB_PANIC) {
		register unsigned i, n, *fp, pc;
		fp = (unsigned *)&paniced - 1;
		while(((int)fp&03)==0 && ((pc = fp[-2])&0xc0000000)==0xc0000000) {
			printf("%x (", fp);
			if(fp[-1] == 0x1fff0004)	/* trap */
				n = 6;
			else
				n = (fp[-1]&0xffff)/4;
			for(i=1; i<n; i++) {
				if(i > 1)
					printf(",");
				printf("%x", fp[i]);
			}
			printf(") from %x\n", pc);
			if(fp[-1] == 0x1fff0004) {	/* trap */
				printf("regs: ");
				for(i= -15; i<=-3; i++) {
					if(i > -15)
						printf(",");
					printf("%x", fp[i]);
				}
				printf("\n");
			}
			fp = *(unsigned **)fp;
			if (fp == NULL) break;
		}
	}
	(void) spl1();
	howto = arghowto;
	if ((howto&RB_NOSYNC)==0 && waittime < 0 && bfreelist[0].b_forw) {
		waittime = 0;
		update();
		printf("syncing disks... ");
#ifdef notdef
		DELAY(10000000);
#else
		{ register struct buf *bp;
		  int iter, nbusy, oldnbusy;

		  printf ("\tBlocks to sync : ");
		  oldnbusy = 0;
		  for (;;) {
			DELAY(1000);
			nbusy = 0;
			for (bp = &buf[nbuf]; --bp >= buf; )
				if ((bp->b_flags & (B_BUSY|B_INVAL)) == B_BUSY)
					nbusy++;
			if (nbusy == 0)
				break;
			if (nbusy != oldnbusy) {
				iter = 0;
				printf("%d ", nbusy);
				oldnbusy = nbusy;
			} else {
				if (++iter >= 100) {
					printf (" - disk I/O stopped (?), giving up\n");
					DELAY(10000);
					break;
				}
			}
		  }
		}
#endif
		printf("done\n\n");
	}
	splx(0x1f);			/* extreme priority */
	devtype = major(rootdev);
	if (howto&RB_HALT) {
		printf("halting (in tight loop); hit <return>~h\n\n");
		mtpr(0x1f,IPL);
		for (;;)
			;
	} else {
		if (paniced == RB_PANIC) {
			doadump();		/* TXDB_BOOT's itsself */
			/*NOTREACHED*/
		}
		tocons(CPBOOT);
	}
	for (;;)
		asm("halt");
	/*NOTREACHED*/
}



/*
 * Send the given comand ('c') to the console processor.
 * Assumed to be one of the last things the OS does before
 *  halting or rebooting.
 */

struct cphdr *lasthdr;	/* Available in "dev/cons.c" */

struct	cpdcb_o cpcontrol;

tocons(command)
int command;
{

	int timeout;

	cpcontrol.cp_hdr.cp_unit = CPUNIT;
	cpcontrol.cp_hdr.cp_comm =  (char) command;
	if (command != CPBOOT) 
		cpcontrol.cp_hdr.cp_count = 1;	/* Just for sanity */
	else {
		cpcontrol.cp_hdr.cp_count = 4;
		*(int *)cpcontrol.cp_buf = 0;	/* r11 value for reboot */
	}
	timeout = 100000;				/* Delay loop */
	while (timeout-- && !(lasthdr->cp_unit & CPDONE))
		uncache(&lasthdr->cp_unit);
					/* Give up, force it to listen */
	mtpr ( vtoph(0, &cpcontrol), CPMDCB);
}

/*
 * Invalidate single all pte's in a cluster
 */
tbiscl(v)
	unsigned v;
{
	register caddr_t addr;		/* must be first reg var */
	register int i;

	addr = ptob(v);
	for (i = 0; i < CLSIZE; i++) {
		mtpr(addr, TBIS);
		addr += NBPG;
	}
}

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, either when called above, or by
 * the auto-restart code.
 */
dumpsys()
{

#ifdef notdef
	if ((minor(dumpdev)&07) != 1)
		return;
#endif
	dumpsize = physmem;
	printf("\ndumping to dev %x, offset %d\n", dumpdev, dumplo);
	printf("dump ");
	switch ((*bdevsw[major(dumpdev)].d_dump)(dumpdev)) {

	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\n");
		break;

	default:
		printf("succeeded\n");
		break;
	}
	printf("Rebooting the system ...\n\n");
	tocons(CPBOOT);
}


/*
 * Bus error 'recovery' code.
 * Print out the buss frame and then give up.
 * (More information from special registers can be printed here.)
 * 
 */

/*
 * Frame for bus error
 */
struct buserframe {
	int	which_bus;		/* primary or secondary */
	int	memerreg;		/* memory error register */
	int	trp_pc;			/* trapped pc */
	int	trp_psl;		/* trapped psl */
};

buserror(busef)
	caddr_t busef;
{
	register struct buserframe *frameptr;
	register long 	hardreg;


	frameptr = (struct buserframe *)busef;
	printf("bus error at address %x, psl = %x\n",
		frameptr->trp_pc,frameptr->trp_psl);
	hardreg =  frameptr->memerreg;
	printf("\tMEAR = %x\n",((hardreg&MEAR)>>16)&0xffff);
	switch (hardreg & ERRCD){
		case (APE): 	printf("\tAdress parity error.Should not reach this point!! \n");
				break;
		case (DPE): 	printf("\tData parity error.\n");
				break;
		case (DCE):	printf("\tData check error.\n");
				break;
		case (VTO):	printf("\tVersabus timeout.\n");
				break;
		case (VBE):	printf("\tVersabus error.Should not reach this point!! \n");
				break;
		case (NEM):	printf("\tNon existent memory.\n");
				break;
		default:	printf("\tUnknown error code: %x\n",
					hardreg&ERRCD);
	}
	if (hardreg&AXE) printf("\tAdapter external error\n");
	printf ("\tError master : ");
	if (hardreg&ERM) printf("Versabus\n");
	else printf ("Tahoe\n");
	if (hardreg&IVV)
	   printf("\tIllegal interrupt vector, from ipl %d\n",
			(hardreg >> 2) & 7);

	hardreg = frameptr->which_bus;
	printf("\tMCBR = %x\n", ((hardreg&MCBR)>>16)&0xffff);
	printf("\tVersabus type : %x\n", hardreg&0xffc3);
	if (frameptr->memerreg&IVV) return;
	panic("buserror");
}


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 = spl8();
	while ((bp->b_flags & B_DONE) == 0)
		sleep((caddr_t)bp, prio);
	splx(s);
}


/*ARGSUSED*/
mtpr (value, regno)
{
	asm("mtpr 4(fp), 8(fp)");
}

/*ARGSUSED*/
int
mfpr (regno)
{
	asm("mfpr 4(fp),r0");
#ifdef lint
	return(0);
#endif
}


unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.