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 */