Ultrix-3.1/sys/sas/md.c

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

/*
 * SCCSID: @(#)md.c	3.0	4/21/86
 */
/**********************************************************************
 *   Copyright (c) Digital Equipment Corporation 1984, 1985, 1986.    *
 *   All Rights Reserved. 					      *
 *   Reference "/usr/src/COPYRIGHT" for applicable restrictions.      *
 **********************************************************************/

/*
 *
 *  File name:
 *
 *	md.c
 *
 *  Source file description:
 *
 *	This module is virtual disk driver to be used with the boot and
 *	other standalone programs. It allows memory to be accessed as a
 *	disk. The main usage for the memory disk is to speed up installation
 *	on systems with 512KB or more memory. The boot "media" is copied
 *	into memory so sdload can access the standalone programs via
 *	this memory disk driver. The base address for memory accesses is
 *	256Kb (after boot/sdload).
 *
 *  Functions:
 *
 *	mdstrategy	handles all read/write memory accesses.
 *
 *  Usage:
 *
 *	md(unit, off)
 *
 *		unit	unit number, ignored but should be zero.
 *		off	offset from 256Kb memory base (512 byte blocks).
 *
 *  Compile:
 *
 *	make libsa.a (cc -c -O md.c)
 *
 *  Modification history:
 *
 *	01 December 1984
 *		File Created -- Fred Canter
 *
 *	09 May 1985
 *		Version 2.1 -- Fred Canter/Bill burns
 *
 *		Bill - chnages for SYSTEM 5 C compiler.
 *		Fred - move memory disk base address from 192KB to 256KB
 *		       for new boot (boot now at 192KB instead of 128KB).
 *
 */

#include <sys/param.h>
#include <sys/inode.h>
#include "saio.h"

#define	PS	((physadr)0177776)

				/* PSW bit definitions */
#define	CMUSER	0140000		/* current mode user */
#define	CMKERN	0		/* current mode kernel */
#define	PMUSER	030000		/* previous mode user */
#define	PMKERN	0		/* previous mode kernel */
#define	SPL7	0340		/* priority level 7 */

#define	KISA0	0172340		/* Memory management PAR/PDR addresses */
#define	KISD0	0172300
#define	UISA0	0177640
#define	UISD0	0177600
#define	KB256	010000		/* PAR value for 256 KB */
#define	PDRVAL0	03406		/* 512 byte page length + read/write access */
#define	PDRVAL1	04006		/* 1024 byte page length + read/write access */

/*
 * segflag -- location of user's buffer i.e., kernel or user space.
 *
 *  3 -	called from user space, shag a kernal par/pdr for mapping
 *	to memory disk area. User's buffer already mapped in user space.
 *
 *  0 - called from kernel space, shag a user par/pdr for mapping
 *	to memory disk area. Shag a second user par/pdr for mapping
 *	to user's buffer in kernel space.
 */
extern	int	segflag;

/*
 * Function:
 *
 *	mdstrategy
 *
 * Function Description:
 *
 *	Performs read/write functions from/to physical memory. Memory
 *	is accessed as if it were a disk, i.e., in units of 512 byte
 *	logical blocks. The layout of memory is as follows:
 *
 *		+---------------+ 0
 *		| stand-alone	|
 *		| program	|
 *		+---------------+ 64KB
 *		| syscall	|
 *		| segment	|
 *		+---------------+ 192KB
 *		| boot / sdload |
 *		| program	|
 *		+---------------+ 256KB
 *		| memory disk	|
 *		:		:
 *		:		:
 *		+---------------+ end of memory (512KB = 512 blocks)
 *
 *	The driver uses memory management PAR/PDR registers to map to
 *	the memory disk and, if the driver is running in kernel mode,
 *	to the user's buffer. The user's buffer is directly mapped if
 *	the driver is running in user mode. The driver checks the value
 *	in the PAR before each memory access and returns an error if the
 *	access would be beyond the end of physical memory. The amount of
 *	available memory (maxmem) in 64 byte clicks is saved in the
 *	devsw[].dv_csr entry for "md" (see conf.c) by the boot program.
 *	The driver runs in kernel mode when a stand-alone program (mkfs,
 *	icheck, rabads, etc.) is running, and in user mode when boot or
 *	sdload is running.
 *
 * Arguments:
 *
 *	struct iob *io	- pointer to I/O block, see saio.h
 *	int	func	- specifies read or write operation, see saio.h
 *
 * Return Values:
 *
 *	The function returns -1 if the read/write failed.
 *	Otherwise it returns the number of bytes transfered.
 *
 * Side Effects:
 *
 *	None
 */

mdstrategy(io, func)
register struct iob *io;
{
	physadr par, pdr;
	int	a0, d0, a1, d1, sps;
	int	wc, wd;
	char	*adr0, *adr1;
	int	*ubp;
	int	errflag;


	if(segflag == 3) {	/* set pointers to segmentation registers */
		par = KISA0;	/* in user mode, shag kernel par/pdr */
		pdr = KISD0;
	} else {
		par = UISA0;	/* in kernel mode, shag user par/pdr */
		pdr = UISD0;
	}
	a0 = par->r[4];		/* save PAR & PDR contents */
	d0 = pdr->r[4];
	if(segflag != 3) {
		a1 = par->r[5];
		d1 = pdr->r[5];
	}
	sps = PS->r[0];		/* save processor status word */
	if(segflag == 3)	/* set current and previous modes in PSW */
		PS->r[0] = (CMUSER|PMKERN|SPL7);
	else
		PS->r[0] = (CMKERN|PMUSER|SPL7);
	par->r[4] = KB256 + (io->i_bn * 8);
	pdr->r[4] = PDRVAL0;
	if(segflag != 3) {
		par->r[5] = (((int)io->i_ma >> 6) & 01777);
		pdr->r[5] = PDRVAL1;
	}
	wc = 0;
	adr0 = 0100000;				/* address for memory disk */
	adr1 = 0120000 + ((int)io->i_ma & 077);	/* user's buffer address */
	if(segflag == 3)	/* don't use adr1, user's buffer is mapped in */
		ubp = io->i_ma;	/* pointer to user's buffer */
	errflag = 0;
	while(wc < (io->i_cc >> 1)) {
		/*
		 * Make sure xfer does not overflow memory.
		 * devsw[].dv_csr = maxmem (memory size in 64 byte clicks)
		 */
		if(par->r[4] >= (unsigned)devsw[io->i_ino.i_dev].dv_csr) {
			printf("\nFATAL ERROR: memory disk - out of memory!\n");
			errflag = 1;
			break;
		}
		if(func == READ) {
			wd = mfpi(adr0);
			if(segflag == 3)
				*ubp = wd;
			else
				mtpi(wd, adr1);
		} else {
			if(segflag == 3)
				wd = *ubp;
			else
				wd = mfpi(adr1);
			mtpi(wd, adr0);
		}
		adr0 += 2;
		adr1 += 2;
		wc++;
		ubp++;
		if((wc % 256) == 0) {
			par->r[4] += 8;
			if(segflag != 3)
				par->r[5] += 8;
			adr0 = 0100000;
			adr1 = 0120000 + ((int)io->i_ma & 077);
		}
	}
	par->r[4] = a0;		/* restore PAR, PDR, PSW */
	pdr->r[4] = d0;
	if(segflag != 3) {
		par->r[5] = a1;
		pdr->r[5] = d1;
	}
	PS->r[0] = sps;
	if(errflag)
		return(-1);
	else
		return(io->i_cc);
}