Google
 

Trailing-Edge - PDP-10 Archives - SRI_NIC_PERM_FS_1_19910112 - c/its/lib/its/humble.c
There are no other files named humble.c in the archive.
/*								-*-C-*-
 *	HUMBLE - Functions for hacking inferiors.
 */

#include "c-env.h"
#include "errno.h"
#include "sys/usysio.h"
#include "sys/usysig.h"
#include "sys/file.h"
#include "sysits.h"
#include "sys/humble.h"

#if !SYS_ITS
#error This is an ITS specific file!
#endif

#define PAGE_SIZE 02000
#define PAGE_MASK 01777
#define LOG_PAGE_SIZE 10
#define PAGE_MAP_SIZE 0400
#define LOG_PAGE_MAP_SIZE 8
#define MEMORY_SIZE 01000000
#define LOG_MEMORY_SIZE 18

#define up_to_page(intptr)\
    ((int *) ((((int) (intptr)) + PAGE_MASK) & ~PAGE_MASK))

#define down_to_page(intptr)\
    ((int *) (((int) (intptr)) & ~PAGE_MASK))

#define up_to_page_number(intptr)\
    ((((int) (intptr)) + PAGE_MASK) >> LOG_PAGE_SIZE)

#define page_number(intptr)\
    (((int) (intptr)) >> LOG_PAGE_SIZE)

#define line_number(intptr)\
    (((int) (intptr)) & PAGE_MASK)
#define N_FRAMES 5

static int frames[(N_FRAMES * PAGE_SIZE) + (PAGE_SIZE - 1)];

static int map[PAGE_MAP_SIZE];	/* page # -> frame # */

static int fjob[N_FRAMES];	/* <job> */
static int fpage[N_FRAMES];	/* page # within that job */
static int foffset[N_FRAMES];	/* address adjustment between jobs */
static int faccess[N_FRAMES];	/* access: */
				/* 0 => no page */
				/* 1 => read only */
				/* 2 => read/write */

static int clock;		/* for L.R.U. scheme */
static int ftime[N_FRAMES];	/* for L.R.U. scheme */

#define get_pointer_bound(addr)\
    (- (((int) ((int *) (addr))) | ~PAGE_MASK))

/* Given a job and an address within that job, return an (int *) pointing
 * to that location mapped into our own address space.  The access can be
 * specified as 1, for read only, or 2, for read/write.  If read/write is
 * requested, the page will be created within the job if it doesn't already
 * exist.
 */
static int *get_pointer(job, addr, access)
  int job, addr, access;
{
    int page, frame;

    if (addr < 020 || addr >= MEMORY_SIZE) return (int *) 0;

    if (fjob[frame = map[page = page_number(addr)]] == job
	    && fpage[frame] == page
	    && faccess[frame] >= access) {
	ftime[frame] = ++clock;
	return (int *) (foffset[frame] + addr);
    }
    {
	int i, val, frame_page;

	if (fjob[frame] != job || fpage[frame] != page) {
	    frame = 0;
	    for (i = 1; i < N_FRAMES; i++) {
		if (ftime[i] < ftime[frame]) frame = i;
	    }
	}

	frame_page = up_to_page_number(frames) + frame;

	val = SYSCALL5("corblk", access > 1 ? SC_IMM(_CBNDW) : SC_IMM(_CBNDR),
			SC_IMM(_JSELF), &frame_page, job, &page);

	if (val == _EROPG && access > 1) {
	    val = SYSCALL4("corblk", SC_IMM(_CBNDW),
			    job, &page, SC_IMM(_JSNEW));
	    if (!val) {
		val = SYSCALL5("corblk", SC_IMM(_CBNDW),
				SC_IMM(_JSELF), &frame_page, job, &page);
	    }
	}

	if (val) {
	    faccess[frame] = 0;
	    return (int *) 0;
	}
	
	map[page] = frame;
	fjob[frame] = job;
	fpage[frame] = page;
	faccess[frame] = access;
	ftime[frame] = ++clock;
	foffset[frame] = (frame_page - page) * PAGE_SIZE;
	return (int *) (foffset[frame] + addr);
    }
}
/* Why the hell isn't there a .CALL version of this? */
static void uclose(ch)
  int ch;
{
#asm
	HRLZ 1,-1(17)
	LSH 1,5
	IOR 1,[.UCLOSE 0,]
	XCT 1
#endasm
}

/* The best source of unique sixbit words */
static int gensym()
{
#asm
	.GENSYM 1,
#endasm
}

/* Damnit, I just want to do a simple BLT! */
static void do_blt(from, to, count)
  int *from, *to, count;
{
#asm
	HRLZ 6,-1(17)
	HRR 6,-2(17)
	MOVE 7,-3(17)
	ADDI 7,-1(6)
	BLT 6,(7)
#endasm
}
/* Creates an inferior, returns an FD or -1 if failure */
int j_create()
{
    int fd, ufx, jname, val;

    USYS_BEG();

    if ((fd = _uiofd()) == -1 || !(ufx = _uiofx()))
	USYS_RETERR(EMFILE);

    _uiobsize[ufx] = 9;
    _uioflgs[ufx] |= _UIO_HANDPACK;	/* Block mode channel */

    do {
	jname = gensym();
	val = SYSCALL5("open", SC_IMC(_BIO), _uioch[ufx],
		       SC_SIX("usr"), SC_IMM(0), &jname);
    } while (val == _ENSMD);	/* Keep trying names until unique */

    if (val) USYS_RETERR(ENOENT);

    _openufx(ufx, (O_WRONLY | O_CREAT | O_TRUNC | O_BSIZE_9));
    _uioufx[fd] = ufx;
    USYS_RET(fd);
}

/* Kills the specified inferior.  Just like close() except it actually
 * destroys the job.  Can only be applied to the last open FD.
 */
int j_kill(fd)
  int fd;
{
    int ufx, val;

    USYS_BEG();

    if (fd < 0 || fd >= OPEN_MAX
	  || !(ufx = _uioufx[fd])
	  || _uiotype[ufx] != _DVUSR	/* Better be a job */
	  || _uionopen[ufx] != 1)	/* This better be the only FD */
	USYS_RETERR(EBADF);

    uclose(_uioch[ufx]);	/* Kill it */
    _uiozcnt[ufx] = 0;		/* Channel now closed, so forget these */

    val = close(fd);		/* Shut down rest of I/O system */
    USYS_RET(val);		/* Pass on any errors from close() */
}
/* Devour the TTY.  Always returns 0.  Can't possibly fail! */
/* (I suppose there should be a .CALL version of this, but...) */
int j_dtty()
{
#asm
	.DTTY
	SETZI 1,
#endasm
}

/* Allow an inferior to make use of the TTY.  Returns 0 if it wins, -1
 * if failure.
 * Possible errors:
 *  - Bad FD.
 *  - Job isn't an inferior.
 */
int j_atty(fd)
  int fd;
{
    int ufx;

    USYS_BEG();

    if (fd < 0 || fd >= OPEN_MAX
	  || !(ufx = _uioufx[fd])
	  || _uiotype[ufx] != _DVUSR)
	USYS_RETERR(EBADF);

    if (SYSCALL1("atty", _uiodnum[ufx]))
	USYS_RETERR(EBADF);

    USYS_RET(0);
}
/* Read a user variable.  Returns 0 if it wins, -1 if failure.
 * VAR is a user variable specifier.  LOC is where to store the result.
 * Possible errors:
 *  - Bad FD.
 *  - No such user variable.
 */
int j_vread(fd, var, loc)
  int fd, var, *loc;
{
    int ufx;

    USYS_BEG();

    if (fd < 0 || fd >= OPEN_MAX
	  || !(ufx = _uioufx[fd])
	  || _uiotype[ufx] != _DVUSR)
	USYS_RETERR(EBADF);

    if (SYSCALL3("usrvar", _uiodnum[ufx], &var, SC_VAL(loc)))
	USYS_RETERR(EINVAL);

    USYS_RET(0);
}

/* Write a user variable.  Returns 0 if it wins, -1 if failure.
 * VAR is a user variable specifier.  VAL is the new value.
 * Possible errors:
 *  - Bad FD.
 *  - No such user variable.
 *  - Can't write into this job.
 */
int j_vwrite(fd, var, val)
  int fd, var, val;
{
    int ufx;

    USYS_BEG();

    if (fd < 0 || fd >= OPEN_MAX
	  || !(ufx = _uioufx[fd])
	  || _uiotype[ufx] != _DVUSR)
	USYS_RETERR(EBADF);

    if (SYSCALL3("usrvar", _uiodnum[ufx], &var, &val))
	USYS_RETERR(EINVAL);

    USYS_RET(0);
}
/* Copies COUNT words from BUF into the inferior starting at ADDR.
 * Creating memory if it doesn't exist.  Normally returns 0.  If error it
 * returns the number of words left to be written.
 * Possible errors:
 *  - Bad FD, negative count, negative or huge address.
 *  - System doesn't have enough virtual address space (temporary).
 *  - Can't write into a foreign job.
 */
int j_write(fd, addr, buf, count)
    int fd, addr, *buf, count;
{
    int ufx, *ptr, n;

    USYS_BEG();

    if (fd < 0 || fd >= OPEN_MAX
	    || !(ufx = _uioufx[fd])
	    || _uiotype[ufx] != _DVUSR) {
	errno = EBADF;
	USYS_RET(count);
    }

    if (count < 0 || addr < 0 || addr >= MEMORY_SIZE) {
	errno = EINVAL;
	USYS_RET(count);
    }

    while (addr < 020 && count > 0) {
	if (SYSCALL3("usrmem", _uiodnum[ufx], &addr, &buf[0])) {
	    errno = EACCES;
	    USYS_RET(count);
	}
	buf++;
	addr++;
	count--;
    }

    while (count > 0) {
	if (!(ptr = get_pointer(_uiodnum[ufx], addr, 2))) {
	    errno = EACCES;
	    USYS_RET(count);
	}
	n = get_pointer_bound(addr);
	if (n > count) n = count;
	do_blt(buf, ptr, n);
	buf += n;
	addr += n;
	count -= n;
    }

    USYS_RET(count);
}
/* Copies COUNT words into BUF from the inferior starting at ADDR.
 * Normally returns 0.  If error, it returns the number of words left to be
 * written.
 * Possible errors:
 *  - Bad FD, negative count, negative or huge address.
 *  - Tried to read nonexistent memory.
 */
int j_read(fd,  addr, buf, count)
    int fd, addr, *buf, count;
{
    int ufx, *ptr, n;

    USYS_BEG();

    if (fd < 0 || fd >= OPEN_MAX
	    || !(ufx = _uioufx[fd])
	    || _uiotype[ufx] != _DVUSR) {
	errno = EBADF;
	USYS_RET(count);
    }

    if (count < 0 || addr < 0 || addr >= MEMORY_SIZE) {
	errno = EINVAL;
	USYS_RET(count);
    }

    while (addr < 020 && count > 0) {
	if (SYSCALL3("usrmem", _uiodnum[ufx], &addr, SC_VAL(&buf[0]))) {
	    errno = EACCES;
	    USYS_RET(count);
	}
	buf++;
	addr++;
	count--;
    }

    while (count > 0) {
	if (!(ptr = get_pointer(_uiodnum[ufx], addr, 1))) {
	    errno = EACCES;
	    USYS_RET(count);
	}
	n = get_pointer_bound(addr);
	if (n > count) n = count;
	do_blt(ptr, buf, n);
	buf += n;
	addr += n;
	count -= n;
    }

    USYS_RET(count);
}
/* Recover file position for file UFX after LOAD or PDUMP system call */
static void correct_pos(ufx)
  int ufx;
{
    int syspos;

    if (SYSCALL2("rfpntr", _uioch[ufx], SC_VAL(&syspos))) return;
    _uiopos[ufx] = ((_uioflgs[ufx] & _UIO_HANDPACK) ?
		    (syspos * _uiobword[ufx]) : syspos);
    _uiozcnt[ufx] = 0;
    _uiocnt[ufx] = 0;
    _uioeof[ufx] = 0;
    return;
}

/* Writes a PDUMP file for the job on the freshly opened file.
 * Returns 0 if we win and -1 if we lose.
 * Possible errors:
 *  - Bad FD for job.
 *  - File FD isn't open to DSK.
 *  - DSK or directory full, etc.
 */
int j_dump(job_fd, file_fd)
    int job_fd, file_fd;
{
    int job_ufx, file_ufx, state = 0;

    USYS_BEG();

    if (job_fd < 0 || job_fd >= OPEN_MAX
	    || !(job_ufx = _uioufx[job_fd])
	    || _uiotype[job_ufx] != _DVUSR
	    || file_fd < 0 || file_fd >= OPEN_MAX
	    || !(file_ufx = _uioufx[file_fd]))
	USYS_RETERR(EBADF);

    if (SYSCALL3("pdump", _uiodnum[job_ufx], _uioch[file_ufx], &state))
	USYS_RETERR(EIO);

    correct_pos(file_ufx);

    USYS_RET(0);
}
/* Loads a PDUMP or SBLK file into the job from the freshly opened file.
 * Returns 0 if we win and -1 if we lose.
 * Possible errors:
 *  - Bad FD for job.
 *  - File FD isn't open to DSK.
 *  - File is in the wrong format.
 */
int j_load(job_fd, file_fd)
    int job_fd, file_fd;
{
    int job_ufx, file_ufx;

    USYS_BEG();

    if (job_fd < 0 || job_fd >= OPEN_MAX
	    || !(job_ufx = _uioufx[job_fd])
	    || _uiotype[job_ufx] != _DVUSR
	    || file_fd < 0 || file_fd >= OPEN_MAX
	    || !(file_ufx = _uioufx[file_fd]))
	USYS_RETERR(EBADF);

    if (SYSCALL2("load", _uiodnum[job_ufx], _uioch[file_ufx]))
	USYS_RETERR(EIO);

    correct_pos(file_ufx);

    USYS_RET(0);
}