V9/sys/sun3/mem.c

Compare this file to the similar file:
Show the results in this format:

#ifndef lint
static	char sccsid[] = "@(#)mem.c 1.1 86/02/03 Copyr 1985 Sun Micro";
#endif

/*
 * Copyright (c) 1985 by Sun Microsystems, Inc.
 */

/*
 * Memory special file
 */

#include "../h/param.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/conf.h"
#include "../h/buf.h"
#include "../h/systm.h"
#include "../h/vm.h"
#include "../h/cmap.h"

#include "../machine/pte.h"
#include "../machine/mmu.h"
#include "../machine/cpu.h"
#include "../machine/eeprom.h"

#define	M_MEM		0	/* /dev/mem - physical main memory */
#define	M_KMEM		1	/* /dev/kmem - virtual kernel memory & I/O */
#define	M_NULL		2	/* /dev/null - EOF & Rathole */
#define	M_MBMEM		3	/* /dev/mbmem - (not supported) */
#define	M_MBIO		4	/* /dev/mbio - (not supported) */
#define M_VME16D16	5	/* /dev/vme16d16 - VME 16bit addr/16bit data */
#define M_VME24D16	6	/* /dev/vme24d16 - VME 24bit addr/16bit data */
#define M_VME32D16	7	/* /dev/vme32d16 - VME 32bit addr/16bit data */
#define M_VME16D32	8	/* /dev/vme16d32 - VME 16bit addr/32bit data */
#define M_VME24D32	9	/* /dev/vme24d32 - VME 24bit addr/32bit data */
#define M_VME32D32	10	/* /dev/vme32d32 - VME 32bit addr/32bit data */
#define M_EEPROM	11	/* /dev/eeprom - on board eeprom device */
#define	M_KMEMR		12	/* /dev/kmemr - public part of kernel memory
				 * (read only) */

/*
 * Check bus type memory spaces for accessibility on this machine
 */
mmopen(dev, flag) 
	dev_t dev;
{
	switch (minor(dev)) {
	case M_MEM:
	case M_KMEM:
	case M_KMEMR:
	case M_NULL:
		/* standard devices */
		break;

	case M_EEPROM:
		/* all Sun-3 machines must have EEPROM */
		break;

	case M_VME16D16:
	case M_VME24D16:
	case M_VME32D16:
	case M_VME16D32:
	case M_VME24D32:
	case M_VME32D32:
		/* SUN3_50 is the only Sun-3 machine w/o VMEbus */
		if (cpu == CPU_SUN3_50) {
			u.u_error = EINVAL;
			return;
		}
		break;

	case M_MBMEM:
	case M_MBIO:
	default:
		/* Unsupported or unknown type */
		u.u_error = EINVAL;
		return;
	}
	return;
}

mmread(dev)
	dev_t dev;
{
	mmrw(dev, B_READ);
}

mmwrite(dev)
	dev_t dev;
{
	mmrw(dev, B_WRITE);
}

mmrw(dev, rw)
	dev_t dev;
{
	register int o;
	register u_int c, v;
	register struct iovec *iov;
	int error = 0;
	int pgsp;

	while (u.u_count > 0 && u.u_error == 0) {
		switch (minor(dev)) {

		case M_MEM:
			v = btop(u.u_offset);
			if (v >= physmem)
				goto fault;
			mapin(mmap, btop(vmmap), v, 1, PG_V | PG_KR);
			o = (int)u.u_offset & PGOFSET;
			c = min((u_int)(NBPG - o), u.u_count);
			c = min(c, (u_int)(NBPG -((int)u.u_base&PGOFSET)));
			iomove((caddr_t)&vmmap[o], c, rw);
			break;

		case M_KMEM:
			c = u.u_count;
			if (kernacc((caddr_t)u.u_offset, c, rw))
				iomove((caddr_t)u.u_offset, c, rw);
			else
				mmpeekio(rw, (caddr_t)u.u_offset, (int)c);
			break;

		case M_KMEMR:
			if (rw == B_WRITE)
				goto fault;
			c = u.u_count;
			if ((u_long)u.u_offset < (u_long)KERNELBASE)
				goto fault;
			if (!kernacc((caddr_t)u.u_offset, c, B_READ))
				goto fault;
			iomove((caddr_t)u.u_offset, c, rw);
			break;

		case M_NULL:
			if (rw == B_WRITE) {
				u.u_offset += u.u_count;
				u.u_count = 0;
			}
			return;

		case M_EEPROM:
			mmeeprom(rw, (caddr_t)u.u_offset, u.u_count);
			break;

		case M_VME16D16:
			if (u.u_offset >= VME16_SIZE)
				goto fault;
			v = u.u_offset + VME16_BASE;
			pgsp = PGT_VME_D16;
			goto vme;

		case M_VME16D32:
			if (u.u_offset >= VME16_SIZE)
				goto fault;
			v = u.u_offset + VME16_BASE;
			pgsp = PGT_VME_D32;
			goto vme;

		case M_VME24D16:
			if (u.u_offset >= VME24_SIZE)
				goto fault;
			v =  u.u_offset + VME24_BASE;
			pgsp = PGT_VME_D16;
			goto vme;

		case M_VME24D32:
			if (u.u_offset >= VME24_SIZE)
				goto fault;
			v =  u.u_offset + VME24_BASE;
			pgsp = PGT_VME_D32;
			goto vme;

		case M_VME32D16:
			pgsp = PGT_VME_D16;
			goto vme;

		case M_VME32D32:
			pgsp = PGT_VME_D32;
			/* FALL THROUGH */

		vme:
			v = btop(v);

			mapin(mmap, btop(vmmap), pgsp | v, 1,
				rw == B_WRITE ? PG_V|PG_KW : PG_V|PG_KR);
			o = (int)u.u_offset & PGOFSET;
			c = min((u_int)(NBPG - o), u.u_count);
			mmpeekio(rw, &vmmap[o], (int)c);
			break;

		}
	}
	return;
fault:
	u.u_error = EFAULT;
	return;
}

mmpeekio(rw, addr, len)
	caddr_t addr;
	int len;
{
	register int c, o;
	short sh;
	char cm;

	while (len > 0) {
		if ((len|(int)addr) & 1) {
			c = sizeof (char);
			if (rw == B_READ) {
				if ((o = peekc(addr)) == -1)
					goto fault;
				cm = o;
			}
			iomove((caddr_t)&cm, c, rw);
			if (u.u_error)
				return;
			if (rw == B_WRITE && pokec(addr, c))
				goto fault;
		} else {
			c = sizeof (short);
			if (rw == B_READ) {
				if ((o = peek((short *)addr)) == -1)
					goto fault;
				sh = o;
			}
			iomove((caddr_t)&sh, c, rw);
			if (u.u_error)
				return;
			if (rw == B_WRITE && poke((short *)addr, sh))
				goto fault;
		}
		addr += c;
		len -= c;
	}
	return;
fault:
	u.u_error = EFAULT;
	return;
}

/*
 * If eeprombusy is true, then the eeprom has just
 * been written to and cannot be read or written
 * until the required 10 MS has passed.  It is
 * assumed that the only way the EEPROM is written
 * is thru the mmeeprom routine.
 */
int eeprombusy = 0;

mmeepromclear()
{

	eeprombusy = 0;
	wakeup((caddr_t)&eeprombusy);
}

mmeeprom(rw, addr, len)
	caddr_t addr;
	int len;
{
	int o, oo;
	int s;
	char c;

	if ((int)addr > EEPROM_SIZE)
		return (EFAULT);

	while (len > 0) {
		if ((int)addr == EEPROM_SIZE)
			goto fault;			/* EOF */

		s = splclock();
		while (eeprombusy)
			sleep((caddr_t)&eeprombusy, PUSER);
		(void) splx(s);

		if (rw == B_WRITE) {
			iomove((caddr_t)&c, 1, rw);
			if (u.u_error)
				return;
			o = c;
			if ((oo = peekc(EEPROM_ADDR + addr)) == -1)
				goto fault;
			/*
			 * Check to make sure that the data is actually
			 * changing before committing to doing the write.
			 * This avoids the unneeded eeprom lock out
			 * and reduces the number of times the eeprom
			 * is actually written to.
			 */
			if (o != oo) {
				if (pokec(EEPROM_ADDR + addr, (char)o))
					goto fault;
				/*
				 * Block out access to the eeprom for
				 * two clock ticks (longer than > 10 MS).
				 */
				eeprombusy = 1;
				timeout(mmeepromclear, (caddr_t)0, 2);
			}
		} else {
			if ((o = peekc(EEPROM_ADDR + addr)) == -1)
				goto fault;
			c = o;
			iomove((caddr_t)&c, 1, rw);
			if (u.u_error)
				return;
		}
		addr += sizeof (char);
		len -= sizeof (char);
	}
	return;
fault:
	u.u_error = EFAULT;
	return;
}

/*ARGSUSED*/
mmmmap(dev, off, prot)
	dev_t dev;
	off_t off;
{
	int pf;

	switch (minor(dev)) {

	case M_MEM:
		pf = btop(off);
		if (pf < physmem)
			return (PGT_OBMEM | pf);
		break;

	case M_VME16D16:
		if (off >= VME16_SIZE)
			break;
		return (PGT_VME_D16 | btop(off + VME16_BASE));

	case M_VME16D32:
		if (off >= VME16_SIZE)
			break;
		return (PGT_VME_D32 | btop(off + VME16_BASE));

	case M_VME24D16:
		if (off >= VME24_SIZE)
			break;
		return (PGT_VME_D16 | btop(off + VME24_BASE));

	case M_VME24D32:
		if (off >= VME24_SIZE)
			break;
		return (PGT_VME_D32 | btop(off + VME24_BASE));

	case M_VME32D16:
		return (PGT_VME_D16 | btop(off));

	case M_VME32D32:
		return (PGT_VME_D32 | btop(off));

	}
	return (-1);
}