BBN-V6/ken/map_page.c

#
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/user.h"
#include "../h/reg.h"
#include "../h/file.h"
#include "../h/inode.h"
#include "../h/seg.h"

#ifdef LCBA

char *lcba_address 128*16;     /* UNIXMIN: left operand is K bytes */
/*
 * UNIXMIN is the minimum amount of memory in core clicks left
 * for non-kernel and non-lcba Unix; lcba_address is a convenient
 * place for main to look at it in initializing lcba_max.
 */

/*
 * map_page system call:
 * includes lim_page, rel_lcba, get_lcba,
 * rel_all, set_lcba, max_lcba, siz_lcba,
 * rel_page, map_page.
 * jsq BBN Tue Jul 25 19:28:56 EDT 1978
 */

/*
 *  Flags for lcba_fs.
 *
 *  The synchronization is an odd solution to the reader-writer
 *  problem, where set_lcba's are writers and exclude all lcba calls
 *  and other lcba calls are readers and are not exclusive except
 *  with set_lcba's.
 */
#define FS_B    1       /* doing set_lcba */
#define FS_W    2       /* waiting on other set_lcba */
#define FS_X    4       /* waiting on other lcba call */

map_page()
{
        register r, *arg, *t;
        int mode; char *offset, *length;
        int i;

        static char lcba_fs;    /* get_lcba synchronization flags */
        static char lcba_fm;    /* synchronization count for other calls */

        r = u.u_ar0[R0];        /* get page from user r0 */

        if (r == -2) {  /* set_lcba */
                spl6();
                while (lcba_fs & FS_B) { /* wait for other set_lcba calls */
                        lcba_fs =| FS_W;
                        sleep (&lcba_fs, PWAIT);
                }
                lcba_fs = (FS_B | FS_X); /* wait for other lcba calls */
                while (lcba_fm) sleep (&lcba_fm, PSLEP);
                lcba_fs =& (~FS_X);
                spl0(); /* synchronized: all other lcba calls waiting on us */
                if (lcba_count) {       /* error: lcba in use */
                        u.u_error = EBUSY;
                } else {
                        length = u.u_arg[0];
                        if (length > lcba_max) { /* error: no core */
				u.u_error = EFBIG;
                        } else { /* do it */
                                if (set_lcba(length)) {
                                        u.u_ar0[R0] = 0;
                                }
                        }
                }
                spl6();
                lcba_fs = 0;    /* let somebody else have a turn */
                wakeup (&lcba_fs);      /* who cares if it's inefficient */
                spl0();         /* to do a wakeup on every set_lcba, */
                return; /* because how often is anybody going to use it? */
        }
        spl6();
        while (lcba_fs) sleep (&lcba_fs, PSLEP);/* wait for any set_lcba's */
        lcba_fm++;      /* increment count of other lcba calls in progress */
        spl0();
	if (r == -7) {  /* lim_page */
		lim_page();
		goto out;
	}
	if (r == -5) {  /* rel_lcba */
                if (u.u_minlcb || u.u_mintlcb) {
                        u.u_error = EBUSY;
                } else {
                        rel_lcba();
                        u.u_ar0[R0] = 0;
                }
                goto out;
        }
        if (r == -4) {  /* get_lcba */
                if(get_lcba()) u.u_ar0[R0] = 0;
                goto out;
        }
        if (r == -3) {  /* rel_all */
                t = &u.u_lcbmd[0];
                arg = &u.u_lcbma[0];
                while (t < &u.u_lcbmd[16]) *arg++ = *t++ = 0;
		u.u_mintlcb = u.u_minlcb = u.u_maxlcb = 0;
                u.u_ar0[R0] = 0;
                rel_lcba();
                goto out;
        }
	if (r == -6) {  /* max_lcba */
		u.u_ar0[R0] = lcba_max;
		goto out;
	}
        if (r == -1) {  /* siz_lcba */
                u.u_ar0[R0] = lcba_size;
                goto out;
        }
        /* rel_page or map_page */
	if ((r < 0) || (u.u_sep?(r > 15):(r > 7))) {/* page is out of bounds */
                u.u_error = EINVAL;
                goto out;
        }
        mode = r;       /* save page for goto out on successful rel_page */
        if (u.u_sep){if (r>7) r =- 8; else r =+ 8;} /* convert to internal form */
        arg = u.u_arg[0];       /* get arg */
        if (arg == 0) { /* rel_page */
                if (u.u_lcbmd[r]) {
                        u.u_lcbmd[r] = 0;
                        u.u_lcbma[r] = 0;
                        if (!u.u_sep) { /* Unix requires copies in data APFs*/
                                i = r + 8;
                                u.u_lcbmd[i] = 0;
                                u.u_lcbma[i] = 0;
                        }
                        u.u_ar0[R0] = mode;     /* goto out saved page number */
                }
                else {
                        u.u_error = EINVAL;
                        goto out;
                }
        }
        else{   /* map_page */

                /* the implicit get_lcba: */
                if (!get_lcba()) goto out;

                /* get other arguments from user space */
                mode = fuword (arg);
                offset = fuword (++arg);
                length = fuword (++arg);
                if (length == 0) { /* zero length is no good */
                        u.u_error = EINVAL;
                        goto out;
                }
                if (offset+length > lcba_size){ /* lcb runs off end of lcba */
                        u.u_error = ENOMEM;
                        goto out;
                }
                i = nseg(length);     /* segments required for lcb */
		if(((r & 07) + i) > 8){ /* lcb runs off end of I or D space */
			u.u_error = ENOSPC;
                        goto out;
                }
                i =+ r;
		if (u.u_clmax) {        /* check cache limits, if any */
			if ((r < u.u_clmin) || (i > u.u_clmax)) {
				u.u_error = EFBIG;
				goto out;
			}
		}
                for (t = &u.u_uisd[r]; t < &u.u_uisd[i]; t++){
                /* for each unix software descriptor register */
                        if (*t) {       /* if page is in use give error */
                                u.u_error = EBUSY;
                                goto out;
                        }
                }
                /* all possible errors have been checked for */
                u.u_ar0[R0] = nseg(length); /* goto out number of pages mapped */
                mode = mode?RO:RW;      /* convert mode to hardware form */

                /* install whole segments in software registers */
                t = &u.u_lcbmd[r];
                arg = &u.u_lcbma[r];
                while (length >= 128) {
                        *t++ = (127 << 8) | mode;
                        *arg++ = offset;
                        length =- 128;
                        offset =+ 128;
                }
                if (length) {   /* install any partial page remaining */
                        *t = ((length - 1) << 8) | mode;
                        *arg = offset;
                }
                if (!u.u_sep) { /* copy i into d space registers */
                        t = &u.u_lcbmd[r];
                        arg = &u.u_lcbmd[r+8];
                        while (t < &u.u_lcbmd[i]) *arg++ = *t++;
                        t = &u.u_lcbma[r];
                        arg = &u.u_lcbma[r+8];
                        while (t < &u.u_lcbma[i]) *arg++ = *t++;
                }
        }
        /* after body of rel_page or map_page, */
        /* recompute min and max lcb page and reset hardware registers */
        t = u.u_lcbmd;
        u.u_minlcb = 0;
        for (r = 8; r < 16; r++){
                if (t[r]){
                        u.u_minlcb = (r&07)+1;
                        break;
                }
        }
        u.u_maxlcb = 0;
        if (u.u_minlcb){
                for (r = 16; r > 8;){
                        if (t[--r]){
                                u.u_maxlcb = (r&07)+1;
                                break;
                        }
                }
        }
        u.u_mintlcb = 0;
        if (u.u_sep) {
                for (r = 0; r < 8; r++) {
                        if (t[r]) {
                                u.u_mintlcb = (r + 1);
                                break;
                        }
                }
        }
        sureg ();       /* install software in hardware registers */
out:
        spl6();
        lcba_fm--;
        if ((lcba_fm == 0) && (lcba_fs & FS_X)) {   /* if nobody's siezed */
                wakeup (&lcba_fm);      /* and set_lcba waiting, wake it up */
        }
        spl0();
        return;
}

#endif  /* on LCBA */