static char rcsid[] = "$Header: iomap.c,v 820.1 86/12/04 19:53:28 root Exp $";
static char sccsid[]="%W% %Y% %Q% %G%";

/************************************************************************
*									*
*				Copyright 1984				*
*			VALID LOGIC SYSTEMS INCORPORATED		*
*									*
*	This listing contains confidential proprietary information	*
*	which is not to be disclosed to unauthorized persons without	*
*	written consent of an officer of Valid Logic Systems 		*
*	Incorporated.							*
*									*
*	The copyright notice appearing above is included to provide	*
*	statutory protection in the event of unauthorized or 		*
*	unintentional public disclosure.				*
*									*
************************************************************************/

/*
 * History:
 * ========
 * jht 860321 -- Board-up/document holes regarding getpagemap() returning -1;
 */

#include "../h/param.h"
#include "../machine/cpu.h"
#include "../s32/vectors.h"
#include "../h/map.h"
#include "../s32/reentrant.h"
#include "../s32dev/useful.h"
#include "../s32dev/regmuck.h"
#define	NBD 1		/* Don't care about specific board number here	*/
#include "../s32dev/vpb.h"
#include "../h/tty.h"
#ifndef	WHITE
#include "../s32dev/vgvar.h"
extern struct Tvgcntl vgcntl[];
#endif	WHITE
#include "../s32/debug.h"

/*
 * "iosetmap()" maps the page containing the argument
 * into ioframe and returns its virtual address:
 * (&ioframe <= retval <= &ioframe + PGMASK).
 *
 * "iounsetmap()" restores the old mapping of ioframe.
 * The two routines use a stack to save the page table entries,
 * and expect to be called at the beginning and end
 * of a system call or interrupt routine.
 *
 * DO NOT sleep with a page still mapped.
 *
 * If the stack depth reaches its maximum, mapping is still done,
 * but iosetmap() raises priority to 6, saving the old priority,
 * and iounsetmap() lowers it.
 * Since there are only 7 device priority levels (0-6),
 * an 8-element stack should be large enough to prevent long disables,
 * unless an interrupt routine caller has lowered
 * its priority with a page still mapped
 * and is itself interrupted by a mapper.
 *
 * Only one page can be mapped by a  process at a time.
 */

/*
 * 'dispmgrseg' is set to the segment number
 * of the display manager segment
 */
extern	int	dispmgrseg;


#define	ESTKSIZE 8		/* 8 for production; 1 to test		*/
#define	PTEBMASK 0X0FFF		/* Funny bits in page table entry	*/

extern	int	setpagemask();
extern	int	panic();

bit32	entrystk[ESTKSIZE],
	*stkp = entrystk;

int	oldpri = -1,		/* Used if ESTKSIZE reached.		*/
	pcount = 0;



 byte *
iosetmap(Mba)
	register bit32 Mba;
{
	register bit32  *sp; 
	register int	 x;
	register u_short t;

	/*DODEBUG(D_PIB,("iosetmap: Mba=0x%x, oldpri=%d ",Mba,oldpri)); */

	if (oldpri != -1) panic("iosetmap"); /* Shouldn't be asking again */

	Mba	&= 0X00FFFFFF;
	oldpri	 = spl6();
	if ((sp=stkp++) < &entrystk[ESTKSIZE-1]) {
        	x	= oldpri;
        	oldpri	= -1;
        	splx(x);
	} else	pcount++; 	/* iounsetmap() will lower priority when done */

#ifdef WHITE
	t = setpagemap(SSEG1_VA>>PGSHFT,(Mba>>PGSHFT));
#else WHITE
#ifdef	M68020
	t = setpagemap(SSEG1_VA>>PGSHFT,(Mba>>PGSHFT)|
		((chipType == CHIPTYPE_68020) ?
			V_NONCACHED :
			V_MBMEM));
#else	M68020
	t = setpagemap(SSEG1_VA>>PGSHFT,(Mba>>PGSHFT)|V_MBMEM);
#endif	M68020
#endif WHITE
	*sp = t;
	/*DODEBUG(D_PIB,("sp=0x%x, t=0x%x, oldpri=%d\n",sp,t,oldpri));*/
	return((byte*)(SSEG1_VA|(Mba&PGMASK)));
}

iounsetmap(Mba)
	register bit32	 Mba;
{
	register u_short e;
	register int	 x;

	/*DODEBUG(D_PIB,("iounsetmap: Mba=0x%x, ",Mba));*/
	Mba &= 0X00FFFFFF;
	x    = spl6();
	e    = setpagemap(SSEG1_VA>>PGSHFT,*(--stkp))&PTEBMASK;
	if (oldpri!= -1) {
		/* Restore old priority if end full stk */
        	x	= oldpri;
        	oldpri	= -1;
	};
	splx(x);

	/*DODEBUG(D_PIB,("e=0x%x, stkp=0x%x, x=%d, oldpri=%d\n",e,stkp,x,oldpri));*/
	if ((e != ((Mba>>PGSHFT)&0X0000FFFF)) || (stkp<entrystk)) 
		panic("iounsetmap");
}


 boolean
regmuck(op,raddr,rval)
	int		op;
	register byte	*raddr, *rval;
{
	label_t		jb;
	label_t		*saved_jb;
	extern	label_t	*nofault;
	register byte	*vaddr;
	boolean		retval;

	/*
	 * Validity check that word operands are word aligned.
	 */
	if ((bit32)raddr&1 && op>BYWRITE) panic("regmuck");

	vaddr = iosetmap(raddr);
	DODEBUG(D_PIB,("regmuck op 0x%x, raddr=0x%x, vaddr=0x%x, *rval=0x%x, ",
		op,raddr,vaddr,(op==MEMPROBE ? 0 : *rval))); 
	saved_jb = nofault;
	if (!setjmp(&jb)) {
		/*
		 * This primes for bus error handling
		 */
        	nofault = &jb;
        	retval  = TRUE;

        	switch(op) {

		case MEMPROBE:	*vaddr	= *vaddr; break;

	        case BYSET:	*vaddr |= *rval; break;

	        case BYCLR:	*vaddr &= ~*rval; break;

	        case BYREAD:	*rval	= *vaddr; break;

	        case BYWRITE:	*vaddr	= *rval; break;

	        case WDSET:	*(bit16 *)vaddr |= *(bit16 *)rval; break;

	        case WDCLR:	*(bit16 *)vaddr &= ~*(bit16 *)rval; break;

	        case WDREAD:	*(bit16 *)rval	 = *(bit16 *)vaddr; break;

	        case WDWRITE:	*(bit16 *)vaddr  = *(bit16*)rval; break;

	        default:	retval = PANIC; break;
        	}
	} else retval = FALSE;
#ifdef	M68020
	/*
	 * We need to allow the write-queue to flush
	 * so that we receive any write-behind busErrors
	 * before we unwind the longjmp() mechanism.
	 */
	flushWriteQueue();
#endif	M68020
	nofault = saved_jb;       /* Restore default bus error handling */
	iounsetmap(raddr);
	if (retval==PANIC) panic("regmuck");
	DODEBUG(D_PIB,("return=%d\n",retval));
	return(retval);
}

#define ASCU   'U'			/* Unprobed memory		 */
#define ASC2   '2'			/* Multiply mapped memory	 */
#define ASCDOT '.'			/* Print for missing memory	 */
#define ASCR   'R'			/* Print for RAM disk can't see	 */
#define ASCD   'D'			/* Print for disk-accessible RAM */
#define ASCS   'S'			/* Print for special 8086 mem	 */
#define ASCK   'K'			/* Print for kernel memory	 */
#define ASCQUE '?'			/* Print for unknown board type	 */
					/* Print 1st letter of bdt.type	 */
					/* for known boards ("V" or "P") */
int			vpbintr();
extern	struct bdt	vgbdt, pibdt;
struct	bdt		*bdts[] = {&pibdt, &vgbdt, (struct bdt*)0};

caddr_t	vgHardCopyMem;
char	vgvpMmem;

/*
 * The physical page number of a page which can
 * be used by s32meminit is the argument.  This is
 * also the first physical page NOT in kernel memory.
 */
s32meminit(kendpg)
	int	kendpg;		/* End of kernel, in pages */
{
	frame		*fp;
	register byte	*work;
	register int	i, j, k;
	u_short		slot;
	register struct bdt	*bdtp;
	extern	short	goprintmap;
	extern	u_short	getpagemap();	/* Returns h/w entry:  can be -1 */

#ifdef WHITE
	slot = setpagemap(SSEG2_VA>>pageshift, kendpg);
#else WHITE
	slot = setpagemap(SSEG2_VA>>pageshift, kendpg|mbmem);
#endif WHITE

	work = (byte *)SSEG2_VA;
	for (j = MBPAGES; --j>=0; ) work[j] = ASCU;

	/*
	 * Passed value of kendpg = btoc(&_end+USIZE+1).
	 * This parameter should not be passed;
	 * or the bounds should be checked.
	 */
	for (i = kendpg; --i>=0; ) if (0==(V_MISSING&(j = getpagemap(i)))) {
		j	&= V_PAGEMASK;
		if (j == (u_short) -1)
			panic("s32meminit/E: getpagemap returned (u_short) -1");
		work[j]	 = (work[j]==ASCU) ? ASCK : ASC2 ;
	}

	/*
	 * Now determine the status
	 * of the Multibus memory.
	 *
	 * BUG: Fix both of these clauses
	 * to use the 'boardmap[]' defined
	 * in machine/mem.h
	 */
#ifdef HIGHVGBOARDS
	for (i = kendpg+1; i<PHYSMEMPAGES; i++)
		if (PROBE((byte*)(i<<PGSHFT))) {
#else HIGHVGBOARDS
	for (i = kendpg+1; i<MBPAGES; i++)
		     if (i<0x400 && i>=0x380) continue; /* VGB,PIB,BAB,3COM */
		else if (i<0x900 && i>=0x800) continue; /* CRB		    */
		else if (i<0xE00 && i>=0xDC0) continue; /* RealChip [2-3]   */
		else if (i<0xF00 && i>=0xE00) continue; /* CGB [0-3]	    */
		else if (i<0xF40 && i>=0xF00) continue; /* RealChip [0-1]   */
		else if (i<0xFF0 && i>=0xFD0) continue; /* RealFast	    */
		else if (PROBE((byte*)(i<<PGSHFT))) {
#endif HIGHVGBOARDS
			if (work[i]==ASCU) {
				if (i<ENDDSKPG) work[i] = ASCD;
				else            work[i] = ASCR;
			} else {
				work[i] = ASC2;
				/* printf("ppno=0x%x\n",i); */
			}
		} else work[i] = ASCDOT;

	/*
	 * Clear the board number
	 * in case we restart UNIX without reboot.
	 */
	for (k=0, bdtp=bdts[0]; bdtp!=(struct bdt *)0; bdtp = bdts[++k]) 
 		bdtp->totboards = 0;

#ifndef WHITE
	/*
	 * Look for Valid peripheral boards.
	 */
#ifdef HIGHVGBOARDS
	for (i=PHYSMEMPAGES; fp=(frame*)(i<<PGSHFT), i<MBPAGES; i+=PGPERSEG) {
#else HIGHVGBOARDS
	for (i = 0x380; fp=(frame*)(i<<PGSHFT), i<0xF00; i+=PGPERSEG) {
#endif HIGHVGBOARDS
        	byte	c, v, *q;
        	short	m = LOOP8086;    /* A harmless program */

		if (i==0x400) {i=0xe00-PGPERSEG; continue;}
        	if (regmuck(WDWRITE,fp,&m)) {/*Something's there */
	   		q = (byte *)fp;
			j = 0;

			/*
			 * Try for VGB or PIB
			 */
			if (i<0x400) {
	   			v = DBIT0; regmuck(BYSET,q+DISCRIM0,&v);
	   			regmuck(BYREAD,q+DISCRIM0,&v); v&=DBIT0;
				if (0==v) ++j;

			/*
			 * Try for CGB
			 */
			} else {
				m=0x2000; regmuck(WDSET,q+0xc400,&m);
				regmuck(WDREAD,q+0xc400,&m); m&=0x2000;
				if (0==m) ++j;
			}

			/*
			 * One of VGB, PIB, CGB
			 */
	   		if (j) {
	        		v = DBIT1;
	        		regmuck(BYSET,q+DISCRIM1,&v);  /* Set DBIT1 */
                		regmuck(BYREAD,q+DISCRIM1,&v); /* Read it. */
           	 		/*printf(" type byte = %x, addr(typebyte)=%x ",v,&v);*/
        			bdtp=(v&DBIT1) ? &vgbdt : &pibdt;
				v = 0;
	        		regmuck(BYWRITE,q+DISCRIM1,&v);  /* Set DBIT1 */
       				/*printf("%s board at %x\n",&bdtp->type,fp);*/
				if ((bdtp->sharebits!=0) && ISSHRBSLOT(bdtp,bdtp->totboards))
					bdtp->totboards++;/* Skip shared mem slot	*/
				if (bdtp->totboards<=bdtp->maxboards)  
					bdtp->b[(bdtp->totboards)++].boardMba=(byte *)fp;
				else printf("%s board at %x: no bdt.b slot.\n",
						&bdtp->type,fp);
				/*
				 * CGB
				 */
				if (i>=0xE00) {
					c='C'; vgcntl[3&(i>>6)].vgtype=c;
				} else {
					c=(bdtp->type>>24)&0XFF;
					if ('V'==c) {
						if (i==0x3f0)vgcntl[0].vgtype=c;
						if (i==0x3a0)vgcntl[1].vgtype=c;
						if (i==0x3b0)vgcntl[2].vgtype=c;
						if (i==0x3c0)vgcntl[3].vgtype=c;
					}
				}
	   		} else c = ASCQUE; /* Maybe BA board or memory */
		} else c = ASCDOT;	   /* Dot signifies missing */

		/*
		 * CGB takes 4 segs
		 */
		j = PGPERSEG; if(i>=0xE00) j <<= 2;
		while (--j>=0) *(work+j+i) = c;
		if (i>=0xE00) i += 3*PGPERSEG;
	};

/* Now allocate multibus memory to the boards.  Do so based on three cells
   in the bdt for that board type: Mbpgs, sharebits and flag.  Mbpgs tells
   how many pages of Multibus are needed. sharebits tells whether the memory
   applies to the board alone or to a group of boards sharing memory. flag
   tells whether the memory must be segment aligned.  If boards share memory,
   the address of memory gotten is stored in the bdtp->b representing the 
   group, not in the b of individual boards in the group.
 */

	for (bdtp=bdts[0],k=0; bdtp!=(struct bdt *)0; /*bdtpdump(bdtp),*/bdtp=bdts[++k]) {
		/* Go through all bdts	*/
		int		addr, needed, left;
		register byte	*physaddr;
		register int	boundary;

		boundary = (bdtp->flag&SEGALIGN) ? SEGSIZE:V_PAGESIZE;
		if (bdtp->totboards>bdtp->maxboards) 
			bdtp->totboards = bdtp->maxboards;
    		if ((needed=bdtp->Mbpgs)>0) 
		for (i=0; i < bdtp->totboards; i += (1<<bdtp->sharebits)) {
	        	if ((physaddr=(byte *)palloc(needed,boundary))!=0) {
		    		DODEBUG(D_PIB,("bdtp addr= %x, i=%x\n",bdtp,i));
				bdtp->b[i].privMba = physaddr;
				addr=(int)physaddr>>pageshift;
				if (vgvpMmem==0) {/* once, if any vgb or pib */
					vgvpMmem++;
					vgHardCopyMem = (char *)palloc(
						btoc(0x10000),SEGSIZE);
					hcminit();
				}
				for (j=addr; j<addr+bdtp->Mbpgs; j++)
					work[j] = ASCS;
			} else {
				if (ISSHRBSLOT(bdtp,i))
					printf("%s group in slot %d: no Multibus memory.\n",
						&bdtp->type, i);
				else 
					printf("%s board at %x: no Multibus memory.\n",
			        		&bdtp->type, bdtp->b[i].boardMba);
		    		bdtp->b[i].flag |= BAD;
			}
	        }
	}	
#endif	WHITE

	IRQ1vector = vpbintr;	/*Define interrupt routine for VPBs	*/

#define NUMPERLN 64		/*Print 64 page statuses per line	*/

	if (goprintmap) for (i=0; i<MBPAGES; i=j) {
		int	k;
		boolean	same;

		printf("\n%06x:%06x ",i<<PGSHFT,((i+NUMPERLN)<<PGSHFT)-1);
		for (k=0; k<NUMPERLN; k++) putchar(*(work+i+k), 0);
		/*
		 * Avoid printing duplicate lines
		 */
		for (j=i, same=TRUE; (j < MBPAGES) && same;) {
			j += NUMPERLN; 
			for (k=0; k<NUMPERLN; k++)
				if (*(work+j+k) != *(work+i+k)) {
					same = FALSE;
					break;
				}
		}
		if (j!=(i+NUMPERLN))
			printf("\n%06x:%06x same as above",
				(i+NUMPERLN)<<PGSHFT,(j<<PGSHFT)-1);
	}

	slot = setpagemap(SSEG2_VA>>pageshift,slot);

	printf("\n");
	return;
}

reentrant(vpbintr)
{
	register int		k;
	register struct bdt*	bdtp;

	for (bdtp=bdts[0],k=0; bdtp!=(struct bdt *)0; bdtp=bdts[++k])
		if (bdtp->intrpt) {
			/*printf("Calling %s int.rtn\n",&bdtp->type);*/
			(*bdtp->intrpt)() ;
		}

	/* reschedule */
	return(1);
}

/*bdtpdump(p)
/*register struct bdt *p;
/*{
/*	printf("bdt at %x\n",p);
/*	printf("  type=%x",p->type);
/*	printf("  altbdt=%x",p->altbdt);
/*	printf("  owner=%x",p->owner);
/*	printf("  mdlegal=%x",p->mdlegal);
/*printf("\n");
/*	printf("  dvcflag=%x",p->dvcflag);
/*	printf("  intpri=%x",p->intpri);
/*	printf("  Mbpgs=%x",p->Mbpgs);
/*	printf("  sharebits=%x",p->sharebits);
/*	printf("  sharemask=%x",p->sharemask);
/*printf("\n");
/*	printf("  minorbits=%x",p->minorbits);
/*	printf("  minormask=%x",p->minormask);
/*	printf("  maxboards=%x",p->maxboards);
/*	printf("  totboards=%x",p->totboards);
/*	printf("  flag=%x",p->flag);
/*	printf("  reserved=%x",p->reserved);
/*printf("\n");
/*	printf("  doio[0]=%x",p->doio[0]);
/*	printf("  intrpt=%x",p->intrpt);
/*	printf("  watch=%x",p->watch);
/*	printf("  onbdend=%x",p->onbdend);
/*	printf("  offbdbase=%x",p->offbdbase);
/*	printf("  segregad[0]=%x",p->segregad[0]);
/*printf("\n");
/*	printf("  run.op=%x",p->run.op);
/*	printf("  run.value=%x",p->run.value);
/*	printf("  run.address=%x",p->run.address);
/*printf("\n");
/*	printf("  halt.op=%x",p->halt.op);
/*	printf("  halt.value=%x",p->halt.value);
/*	printf("  halt.address=%x",p->halt.address);
/*printf("\n");
/*	printf("  redled.op=%x",p->redled.op);
/*	printf("  redled.value=%x",p->redled.value);
/*	printf("  redled.address=%x",p->redled.address);
/*printf("\n");
/*	printf("  greenled.op=%x",p->greenled.op);
/*	printf("  greenled.value=%x",p->greenled.value);
/*	printf("  greenled.address=%x",p->greenled.address);
/*printf("\n");
/*	printf("  ring.op=%x",p->ring.op);
/*	printf("  ring.value=%x",p->ring.value);
/*	printf("  ring.address=%x",p->ring.address);
/*printf("\n");
/*	printf("  b[0].privMba=%x",p->b[0].privMba);
/*	printf("  b[0].boardMba=%x",p->b[0].boardMba);
/*	printf("  b[0].curaddr=%x",p->b[0].curaddr);
/*printf("\n");
/*	printf("  b[0].start[0]=%x",p->b[0].start[0]);
/*	printf("  b[0].start[1]=%x",p->b[0].start[1]);
/*	printf("  b[0].start[2]=%x",p->b[0].start[2]);
/*	printf("  b[0].start[3]=%x",p->b[0].start[3]);
/*printf("\n");
/*	printf("  b[0].diagsig=%x",p->b[0].diagsig);
/*	printf("  b[0].mdopen=%x",p->b[0].mdopen);
/*	printf("  b[0].flag=%x",p->b[0].flag);
/*	printf("  b[0].reserved=%x",p->b[0].reserved);
/*printf("\n");
/*}
*/
