#ifdef MEMORYMAPPING

#include "../machine/pte.h"
#include "../machine/mtpr.h"

#include "../h/types.h"
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/file.h"
#include "../h/buf.h"
#include "../h/dir.h"
#include "../h/signal.h"
#include "../h/user.h"
#include "../h/proc.h"
#include "../h/cmap.h"
#include "../h/map.h"
#include "../h/vm.h"
#include "../h/vmmac.h"

#include "../rciext/section.h"

struct cmap_list section_cmaps[CMAP_LIST_SIZE];
struct proc_list section_procs[PROC_LIST_SIZE];
struct section sections[N_SECTIONS];
struct pfn_section pfn_sections[N_PFN_SECTIONS];
int top_section;

int debugmemfree = 0;

int n_pages_locked = 0;

int section_lock_var = 0;
int section_verbose = 0;

static int strcmp(a,b)
char *a;
char *b;
{
 while (1)
  { if (*a != *b)
     { return(*a - *b);
     }
    if (*a == '\0')
     { return(0);
     }
    a ++;
    b ++;
  }
}

static strcpy(a,b)
char *a;
char *b;
{
 while (*a++ = *b++) ;
}

static int get_name(src,dst)
register char *src;
register char *dst;
{
 register int i;
 register int j;

 for (i=0;i<SEC_NAMLEN;i++)
  { j = fubyte(src++);
    if (j < 0)
     { u.u_error = EFAULT;
       return(1);
     }
    *dst++ = j;
    if (j == 0)
     { break;
     }
  }
 if (i == 0)
  { u.u_error = EINVAL;
    return(1);
  }
 if (j != 0)
  { *dst++ = '\0';
  }
 return(0);
}

section_lock()
{
 register int s;

 if (section_verbose)
  { printf("\t\tsection_lock()\n");
  }
 s = splhigh();
 while (section_lock_var != 0)
  { if (section_verbose)
     { printf("\t\tlock taken\n");
     }
    sleep(&section_lock_var,PZERO+1);
  }
 section_lock_var = 1;
 splx(s);
 if (section_verbose)
  { printf("\t\tgot lock\n");
  }
 return;
}

section_unlock()
{
 int s;

 if (section_verbose)
  { printf("\t\tsection_unlock()\n");
  }
 s = splhigh(); /* just in case */
 section_lock_var = 0;
 splx(s);
 wakeup(&section_lock_var);
 if (section_verbose)
  { printf("\t\tdone\n");
  }
}

struct proc_list *new_proc_list()
{
 struct proc_list *p;

 p = section_procs[0].flink;
 if (p == &section_procs[0])
  { return(0);
  }
 section_procs[0].flink = p->flink;
 p->flink->blink = &section_procs[0];
 return(p);
}

free_proc_list(p)
struct proc_list *p;
{
 p->flink = section_procs[0].flink;
 p->blink = &section_procs[0];
 p->flink->blink = p;
 p->blink->flink = p;
}

struct cmap_list *new_cmap_list()
{
 struct cmap_list *c;

 if (section_cmaps[0].link == &section_cmaps[0])
  { return(0);
  }
 c = section_cmaps[0].link;
 section_cmaps[0].link = c->link;
 return(c);
}

free_cmap_list(c)
struct cmap_list *c;
{
 c->link = section_cmaps[0].link;
 section_cmaps[0].link = c;
}

free_all_mapping(p) /* called from exit() and exec() code */
struct proc *p;
{
 register int i;

 if (section_verbose)
  { printf("free_all_mapping for proc %d\n",p->p_pid);
  }
 section_lock();
 if (section_verbose)
  { printf("\tlocked\n");
  }
 for (i=0;i<top_section;i++)
  { if (sections[i].name[0])
     { register struct proc_list *q;
       register struct proc_list *r;
       register struct proc_list *qq;
       r = &sections[i].proc_root;
       for (q=r->flink;q!=r;q=qq)
	{ qq = q->flink;
	  if (q->proc == p)
	   { section_unmap(p,&sections[i],q);
	   }
	}
       if (sections[i].lock == p)
	{ sections[i].lock = 0;
	}
     }
  }
 for (i=0;i<N_PFN_SECTIONS;i++)
  { if (pfn_sections[i].proc == p)
     { unmap_pfnsec(&pfn_sections[i]);
     }
  }
 section_unlock();
 if (section_verbose)
  { printf("\tdone\n");
  }
}

map_to(p,s,va)
struct proc *p;
struct section *s;
caddr_t va;
{
 struct proc_list *pl;
 struct cmap_list *c;
 int i;

 if (section_verbose)
  { printf("\tmap_to(proc%d,section%d,va%x)\n",p->p_pid,s-sections,va);
  }
 if (s->name[0] == '\0')
  { panic("map_to on unmapped section\n");
  }
 pl = new_proc_list();
 if (pl == 0)
  { u.u_error = ETABLEFULL;
    return;
  }
 if (section_verbose)
  { printf("\tgot proc list\n");
  }
 pl->flink = s->proc_root.flink;
 pl->blink = &s->proc_root;
 pl->flink->blink = pl;
 pl->blink->flink = pl;
 pl->proc = p;
 pl->virtaddr = va;
 if (section_verbose)
  { printf("\tlinked proc list in\n");
  }
 c = s->pages;
 for (i=0;i<s->size;i++)
  { struct pte *pte;
    int pf;
    int j;
    int si;
    struct cmap *cmapp;
	
    if (section_verbose)
     { printf("\tfor cluster %d\n",i);
     }
    si = splimp();
    pte = vtopte(p,btop(va+(i*CLBYTES)));
    pf = Usrptmap[btokmx((struct pte *)c->kva)].pg_pfnum;
    if (section_verbose)
     { printf("\tmunlock()ing\n");
     }
    cmapp = &cmap[pgtocm(pte->pg_pfnum)];
    MUNLOCK(cmapp);
    if (section_verbose)
     { printf("\tmemfree()ing\n");
     }
    memfree(pte,CLSIZE,1);
    if (section_verbose)
     { printf("\tmlock()ing\n");
     }
    cmapp = &cmap[pgtocm(pf)];
    if (! (c->waslocked = cmapp->c_lock))
     { MLOCK(cmapp);
     }
    if (section_verbose)
     { printf("\tsetting ptes\n");
     }
    for (j=0;j<CLSIZE;j++)
     { struct pte k;
       k = *pte;
       k.pg_pfnum = pf;
       *pte = k;
       pte ++;
       pf ++;
     }
    pf -= CLSIZE;
    cmap[pgtocm(pf)].c_refcnt ++;
    pf ++;
    mtpr(TBIA,0);
    splx(si);
    c = c->link;
  }
 if (section_verbose)
  { printf("\tunlocking cmaps\n");
  }
 c = s->pages;
 for (i=0;i<s->size;i++)
  { int si;
    si = splimp();
    if (! c->waslocked)
     { struct cmap *cmapp;
       int pfn = Usrptmap[btokmx((struct pte *)c->kva)].pg_pfnum;
       cmapp = &cmap[pgtocm(pfn)];
       MUNLOCK(cmapp);
     }
    splx(si);
    c = c->link;
  }
 if (section_verbose)
  { printf("\tmap_to done\n");
  }
}

map_new(p,name,s,size,va)
struct proc *p;
char *name;
struct section *s;
int size;
caddr_t va;
{
 struct proc_list *pl;
 struct cmap_list *c;
 int i;

 if (section_verbose)
  { printf("\tmap_new(proc%d,\"%s\",section%d,size%d,va%x)\n",
			p->p_pid,name,s-sections,size,va);
  }
 if (s->name[0])
  { panic("map_new on already mapped section");
  }
 s->proc_root.proc = 0;
 s->proc_root.virtaddr = 0;
 s->size = size;
 s->lock = 0;
 pl = new_proc_list();
 if (pl == 0)
  { u.u_error = ETABLEFULL;
    return;
  }
 s->proc_root.flink = pl;
 s->proc_root.blink = pl;
 pl->flink = &s->proc_root;
 pl->blink = &s->proc_root;
 pl->proc = p;
 pl->virtaddr = va;
 s->pages = 0;
 for (i=0;i<size;i++)
  { c = new_cmap_list();
    if (c == 0)
     { while (s->pages)
	{ c = s->pages->link;
	  free_cmap_list(s->pages);
	  s->pages = c;
	}
       free_proc_list(pl);
       u.u_error = ETABLEFULL;
       return;
     }
    c->link = s->pages;
    s->pages = c;
  }
 c = s->pages;
 for (i=0;i<size;i++)
  { int a;
    struct pte *pte;
    unsigned int pf;
    int si;
    caddr_t v;
    int j;
    si = splimp();
    a = rmalloc(kernelmap,(long)CLSIZE);
    if (a == 0)
     { c = s->pages;
       for (;j>0;j--)
	{ rmfree(kernelmap,(long)CLSIZE,(long)btokmx((struct pte *)c->kva));
	  c = c->link;
	}
       splx(si);
       while (s->pages)
	{ c = s->pages->link;
	  free_cmap_list(s->pages);
	  s->pages = c;
	}
       free_proc_list(pl);
       u.u_error = ENOMEM;
       return;
     }
    c->kva = (caddr_t) kmxtob(a);
    v = va + (i*CLBYTES);
    pte = vtopte(p,btop(v));
    pf = pte->pg_pfnum;
    pte = &Usrptmap[a];
    for (j=0;j<CLSIZE;j++)
     { *(int *)pte++ = pf++;
     }
    vmaccess(&Usrptmap[a],c->kva,CLSIZE);
    pf -= CLSIZE;
    cmap[pgtocm(pf)].c_ulock = 0;
    cmap[pgtocm(pf++)].c_refcnt = 2; /* one each for user and kernel */
    mtpr(TBIA,0);
    splx(si);
    c = c->link;
  }
 c = s->pages;
 for (i=0;i<size;i++)
  { int pf;
    int si;
    struct cmap *cmapp;

    si = splimp();
    pf = Usrptmap[btokmx((struct pte *)c->kva)].pg_pfnum;
    cmapp = &cmap[pgtocm(pf)];
    if (cmapp->c_lock)
     { MUNLOCK(cmapp);
     }
    splx(si);
    c = c->link;
  }
 strcpy(s->name,name);
 if (section_verbose)
  { printf("\tmap_new done\n");
  }
}

map_physical(p,pfn,size,va)
struct proc *p;
int pfn;
int size;
caddr_t va;
{
 struct pfn_section *s;
 struct cmap_list *c;
 unsigned int pf;
 int i;
 int si;

 if (section_verbose)
  { printf("\tmap_physical(proc%d,pfn%x,size%d,va%x)\n",p->p_pid,pfn,size,va);
  }
 for (i=0;i<N_PFN_SECTIONS;i++)
  { s = &pfn_sections[i];
    if (s->proc == 0)
     { break;
     }
  }
 if (i >= N_PFN_SECTIONS)
  { u.u_error = ETABLEFULL;
    return;
  }
 if (section_verbose)
  { printf("\t\tusing section %d\n",s-pfn_sections);
  }
 s->proc = p;
 s->virtaddr = va;
 s->size = size;
 pf = pfn;
 for (i=0;i<size;i++)
  { caddr_t v;
    struct pte *pte;
    struct cmap *cmapp;
    struct pte proto;
    int si;
    int j;
    v = va + (i*CLBYTES);
    pte = vtopte(p,btop(v));
    si = splimp();
    j = pgtocm(pte->pg_pfnum);
    if ((j < 0) || (j >= ncmap))
     { if (section_verbose)
	{ printf("\tnot vmemfree()ing because pfn %d not a good cmap\n",(int)pte->pg_pfnum);
	}
     }
    else
     { extern int debugmemfree;
       if (section_verbose)
	{ int i;
	  struct cmap *c;
	  i = pgtocm(pte->pg_pfnum);
	  c = &cmap[i];
	  printf("\tvmemfree()ing, pte=%x, cmap=%d, refcnt=%d, ulock=%d\n",(int)pte,c-cmap,c->c_refcnt,c->c_ulock);
	}
       debugmemfree = section_verbose;
       MUNLOCK(&cmap[pgtocm(pte->pg_pfnum)]);
       p->p_rssize -= vmemfree(pte,CLSIZE);
       debugmemfree = 0;
     }
    *(int *)&proto = PG_V | PG_UW;
    for (j=0;j<CLSIZE;j++)
     { proto.pg_pfnum = pf++;
       *(int *)pte++ = *(int *)&proto;
     }
    mtpr(TBIA,0);
    splx(si);
  }
 if (section_verbose)
  { printf("\tmap_physical done\n");
  }
}

delete_section(s)
struct section *s;
{
 struct cmap_list *cml;
 struct cmap_list *next;

 if (section_verbose)
  { printf("\tdelete_section(%d)\n",s-sections);
  }
 if (s->proc_root.flink != &s->proc_root)
  { panic("delete mapped section");
  }
 for (cml=s->pages;cml;cml=next)
  { register int i;
    register int pf;
    struct cmap *cmapp;

    next = cml->link;
    pf = Usrptmap[btokmx((struct pte *)cml->kva)].pg_pfnum;
    cmapp = &cmap[pgtocm(pf)];
    (cmapp->c_refcnt)--;
    if (cmapp->c_lock)
     { MUNLOCK(cmapp);
     }
    pf ++;
    wmemfree(cml->kva,CLBYTES);
    free_cmap_list(cml);
  }
 s->name[0] = '\0';
 while ((top_section > 0) && (sections[top_section-1].name[0] == '\0'))
  { top_section --;
  }
 if (section_verbose)
  { printf("\tdelete_section done\n");
  }
}

section_unmap(p,s,q)
struct proc *p;
struct section *s;
struct proc_list *q;
{
 struct pte *pte;
 caddr_t va;
 int i;
 struct pte proto;
 int si;

 if (section_verbose)
  { printf("\tsection_unmap(proc%d,section%d,proc_list%x)\n",p->p_pid,s-sections,(int)q);
  }
 si = splimp();
 if (!isadsv(p,btop(q->virtaddr)))
  { panic("unmapping from non-data segment");
  }
 pte = dptopte(p,vtodp(p,btop(q->virtaddr)));
 for (i=0;i<s->size;i++)
  { register int pf = (pte+(i*CLSIZE))->pg_pfnum;
    cmap[pgtocm(pf)].c_refcnt --;
  }
 p->p_rssize -= vmemfree(pte,CLSIZE*s->size);
 *(int *)&proto = PG_UW;
 proto.pg_fod = 1;
 ((struct fpte *)&proto)->pg_fileno = PG_FZERO;
 for (i=(CLSIZE*s->size)-1;i>=0;i--)
  { *(int *)(pte+i) = *(int *)&proto;
  }
 mtpr(TBIA,0);
 q->flink->blink = q->blink;
 q->blink->flink = q->flink;
 q->flink = section_procs[0].flink;
 q->blink = &section_procs[0];
 q->flink->blink = q;
 q->blink->flink = q;
 splx(si);
 if (s->proc_root.flink == &s->proc_root)
  { delete_section(s);
  }
 if (section_verbose)
  { printf("\tsection_unmap done\n");
  }
}

unmap_pfnsec(s)
register struct pfn_section *s;
{
 register struct pte *pte;
 register struct proc *p;
 struct pte proto;
 int i;
 int si;

 p = s->proc;
 if (! p)
  { panic("unmap_pfnsec: not mapped");
  }
 if (section_verbose)
  { printf("\tunmap_pfnsec(proc%d,va%x)\n",p->p_pid,(int)s->virtaddr);
  }
 si = splimp();
 if (!isadsv(p,btop(s->virtaddr)))
  { panic("unmap_pfnsec: non-data segment");
  }
 pte = dptopte(p,vtodp(p,btop(s->virtaddr)));
 *(int *)&proto = PG_UW;
 proto.pg_fod = 1;
 ((struct fpte *)&proto)->pg_fileno = PG_FZERO;
 for (i=(CLSIZE*s->size)-1;i>=0;i--)
  { *(int *)(pte+i) = *(int *)&proto;
  }
 mtpr(TBIA,0);
 splx(si);
 s->proc = 0;
 if (section_verbose)
  { printf("\tunmap_pfnsec done\n");
  }
}

free_locked_page()	/* called by memfree() */
{
 register int s;

 s = splhigh();
 if (section_verbose)
  { printf("free_locked_page()\n");
  }
 n_pages_locked --;
 splx(s);
}

sectioninit()
{
 register int i;

 for (i=0;i<N_SECTIONS;i++)
  { sections[i].name[0] = '\0';
  }
 for (i=0;i<N_PFN_SECTIONS;i++)
  { pfn_sections[i].proc = 0;
  }
 top_section = 0;
 for (i=CMAP_LIST_SIZE-1;i>0;i--) /* so the chain is backwards....big deal */
  { section_cmaps[i].link = &section_cmaps[i-1];
  }
 section_cmaps[0].link = &section_cmaps[CMAP_LIST_SIZE-1];
 section_cmaps[1].link = 0;
 for (i=0;i<PROC_LIST_SIZE;i++)
  { section_procs[i].flink = &section_procs[i+1];
    section_procs[i].blink = &section_procs[i-1];
  }
 section_procs[0].blink = &section_procs[PROC_LIST_SIZE-1];
 section_procs[PROC_LIST_SIZE-1].flink = &section_procs[0];
}

section_syscall_map_section()
{
 struct a {
   caddr_t addr;
   int size;
   char *name; } *uap = (struct a *) u.u_ap;
 char name[SEC_NAMLEN+1];
 char *cp;
 int i;
 int j;

 if (uap->size & CLOFSET)
  { u.u_error = EALIGN;
    return;
  }
 if (!claligned(uap->addr))
  { u.u_error = EALIGN;
    return;
  }
 if (!useracc(uap->addr,uap->size,B_WRITE))
  { u.u_error = EFAULT;
    return;
  }
 if ( !isadsv(u.u_procp,btop(uap->addr            )) ||
      !isadsv(u.u_procp,btop(uap->addr+uap->size-1)) )
  { u.u_error = EINVAL;
    return;
  }
 if (get_name(uap->name,name))
  { return;
  }
 if (section_verbose)
  { printf("proc %d map %d at %x name %s\n",
		u.u_procp->p_pid,uap->size,uap->addr,name);
  }
 u.u_procp->p_flag |= SULOCK;
 vslock(uap->addr,uap->size);
 if (section_verbose)
  { printf("\tvslock()ed\n");
  }
 section_lock();
 if (section_verbose)
  { printf("\tlocked\n");
  }
 j = -1;
 for (i=0;i<top_section;i++)
  { if ((j < 0) && (sections[i].name[0] == '\0'))
     { j = i;
     }
    else if (strcmp(sections[i].name,name) == 0)
     { break;
     }
  }
 if (i < top_section)
  { if (uap->size/CLBYTES != sections[i].size)
     { u.u_error = EMISMATCH;
     }
    else
     { map_to(u.u_procp,&sections[i],uap->addr);
     }
  }
 else
  { if (j < 0)
     { if (top_section >= N_SECTIONS)
	{ u.u_error = ETABLEFULL;
	}
       else
	{ j = top_section ++;
	}
     }
    if (j >= 0)
     { map_new(u.u_procp,name,&sections[j],uap->size/CLBYTES,uap->addr);
     }
  }
 if (section_verbose)
  { printf("\tfinished\n");
  }
 section_unlock();
 if (section_verbose)
  { printf("\tunlocked\n");
    printf("\tdone\n");
  }
}

section_syscall_map_physical()
{
 struct a {
   caddr_t addr;
   int size;
   int pfn; } *uap = (struct a *) u.u_ap;
 char name[SEC_NAMLEN+1];
 char *cp;
 int i;
 int j;

 if (uap->size & CLOFSET)
  { u.u_error = EALIGN;
    return;
  }
 if (!claligned(uap->addr))
  { u.u_error = EALIGN;
    return;
  }
 if (!useracc(uap->addr,uap->size,B_WRITE))
  { u.u_error = EFAULT;
    return;
  }
 if ( !isadsv(u.u_procp,btop(uap->addr            )) ||
      !isadsv(u.u_procp,btop(uap->addr+uap->size-1)) )
  { u.u_error = EINVAL;
    return;
  }
 if (section_verbose)
  { printf("proc %d map %d at %x physical %x\n",
		u.u_procp->p_pid,uap->size,uap->addr,uap->pfn);
  }
 u.u_procp->p_flag |= SULOCK;
 vslock(uap->addr,uap->size);
 if (section_verbose)
  { printf("\tvslock()ed\n");
  }
 section_lock();
 if (section_verbose)
  { printf("\tlocked\n");
  }
 map_physical(u.u_procp,uap->pfn,uap->size/CLBYTES,uap->addr);
 if (section_verbose)
  { printf("\tfinished\n");
  }
 section_unlock();
 if (section_verbose)
  { printf("\tunlocked\n");
    printf("\tdone\n");
  }
}

section_syscall_unmap()
{
 struct a {
   caddr_t addr; } *uap = (struct a *) u.u_ap;
 char *cp;
 struct section *s;
 struct proc_list *p;
 int i;

 if (section_verbose)
  { printf("proc %d unmap at %x\n",u.u_procp->p_pid,uap->addr);
  }
 section_lock();
 if (section_verbose)
  { printf("\tlocked\n");
  }
 for (i=0;i<top_section;i++)
  { for (p=sections[i].proc_root.flink;p!=&sections[i].proc_root;p=p->flink)
     { if ((p->proc == u.u_procp) && (p->virtaddr == uap->addr))
	{ section_unmap(u.u_procp,&sections[i],p);
	  if (section_verbose)
	   { printf("\tunlocking\n");
	   }
	  section_unlock();
	  if (section_verbose)
	   { printf("\tdone\n");
	   }
	  return;
	}
     }
  }
 for (i=0;i<N_PFN_SECTIONS;i++)
  { register struct pfn_section *s;
    s = &pfn_sections[i];
    if ((s->proc == u.u_procp) && (s->virtaddr == uap->addr))
     { unmap_pfnsec(s);
       section_unlock();
       if (section_verbose)
	{ printf("\tunlocked\n");
	}
       return;
     }
  }
 u.u_error = EINVAL;
 if (section_verbose)
  { printf("\tnot mapped at %x\n",uap->addr);
  }
 section_unlock();
 if (section_verbose)
  { printf("\tunlocked\n");
  }
}

section_syscall_lock()
{
 struct a {
   char *name;
   int block; } *uap = (struct a *) u.u_ap;
 char name[SEC_NAMLEN+1];
 char *cp;
 int i;
 struct section *s;
 register struct proc_list *r;
 register struct proc_list *q;
 struct proc *p;

 if (get_name(uap->name,name))
  { return;
  }
 if (section_verbose)
  { printf("lock(\"%s\")\n",name);
  }
 section_lock();
 if (section_verbose)
  { printf("\tlocked\n");
  }
 for (i=0;i<top_section;i++)
  { if (strcmp(name,sections[i].name) == 0)
     { break;
     }
  }
 if (i >= top_section)
  { u.u_error = EINVAL;
    if (section_verbose)
     { printf("\tno such section\n");
     }
    section_unlock();
    if (section_verbose)
     { printf("\tunlocked\n");
     }
    return;
  }
 p = u.u_procp;
 s = &sections[i];
 r = &s->proc_root;
 for (q=r->flink;q!=r;q=q->flink)
  { if (q->proc == p)
     { break;
     }
  }
 if (q == r)
  { u.u_error = EINVAL;
    if (section_verbose)
     { printf("\tnot mapped to this section\n");
     }
    section_unlock();
    if (section_verbose)
     { printf("\tunlocked\n");
     }
    return;
  }
 if (s->lock == 0)
  { s->lock = u.u_procp;
    if (section_verbose)
     { printf("\ttook lock\n");
     }
  }
 else if (s->lock == u.u_procp)
  { if (section_verbose)
     { printf("\talready have lock\n");
     }
  }
 else if (! uap->block)
  { u.u_error = EWOULDBLOCK;
    if (section_verbose)
     { printf("\twould block\n");
     }
    section_unlock();
    if (section_verbose)
     { printf("\tunlocked\n");
     }
    return;
  }
 else
  { while (s->lock)
     { if (section_verbose)
	{ printf("\tlock already taken\n");
	}
       section_unlock();
       if (section_verbose)
	{ printf("\tunlocked\n");
	}
       sleep((caddr_t)s->lock,PZERO+1);
       if (section_verbose)
	{ printf("\tawakened\n");
	}
       section_lock();
       if (section_verbose)
	{ printf("\tlocked\n");
	}
     }
    s->lock = u.u_procp;
    if (section_verbose)
     { printf("\tfinally took lock\n");
     }
  }
 section_unlock();
 if (section_verbose)
  { printf("\tlocked\n");
  }
}

section_syscall_unlock()
{
 struct a {
   char *name; } *uap = (struct a *) u.u_ap;
 char name[SEC_NAMLEN+1];
 char *cp;
 int i;
 struct section *s;

 if (get_name(uap->name,name))
  { return;
  }
 if (section_verbose)
  { printf("unlock(\"%s\")\n",name);
  }
 section_lock();
 if (section_verbose)
  { printf("\tlocked\n");
  }
 for (i=0;i<top_section;i++)
  { if (strcmp(name,sections[i].name) == 0)
     { break;
     }
  }
 if (i >= top_section)
  { u.u_error = EINVAL;
    if (section_verbose)
     { printf("\tno such section\n");
     }
    section_unlock();
    if (section_verbose)
     { printf("\tunlocked\n");
     }
    return;
  }
 s = &sections[i];
 if (s->lock == u.u_procp)
  { s->lock = 0;
    wakeup((caddr_t)s->lock);
  }
 else
  { u.u_error = EINVAL;
    if (section_verbose)
     { printf("\tdon't have lock\n");
     }
  }
 section_unlock();
 if (section_verbose)
  { printf("\tunlocked\n");
  }
}

section_syscall_dump()
{
 int i;
 char *cmap_map;
 char *proc_map;
 register struct cmap_list *cml;
 register struct proc_list *pl;
 register struct proc_list *r;
 char *zmemall();

 cmap_map = zmemall(memall,CMAP_LIST_SIZE);
 proc_map = zmemall(memall,PROC_LIST_SIZE);
 section_lock();
 printf("\n\n\n\tSection dump\n\n");
 printf("N_SECTIONS=%d, CMAP_LIST_SIZE=%d, PROC_LIST_SIZE=%d\n",
				N_SECTIONS,CMAP_LIST_SIZE,PROC_LIST_SIZE);
 printf("top_section=%d\n",top_section);
 for (i=0;i<top_section;i++)
  { struct section *s = &sections[i];
    printf("Section %d: ",i);
    if (s->name[0])
     { printf("\"%s\", %d klusters (%d bytes)\n",
				s->name,s->size,s->size*CLBYTES);
       printf("\tPage frames: ");
       for (cml=s->pages;cml;cml=cml->link)
	{ int pf = Usrptmap[btokmx((struct pte *)cml->kva)].pg_pfnum;
	  int i;
	  printf(" [%d]",cmap[pgtocm(pf)].c_refcnt);
	  for (i=0;i<CLSIZE;i++)
	   { if (i > 0)
	      { printf("-");
	      }
	     printf("%x",pf++);
	   }
	  cmap_map[cml-section_cmaps] ++;
	}
       printf("\n\tProcesses: ");
       r = &s->proc_root;
       for (pl=r->flink;pl!=r;pl=pl->flink)
	{ printf(" %d",pl->proc->p_pid);
	  proc_map[pl-section_procs] ++;
	}
       printf("\n");
     }
    else
     { printf("not mapped\n");
     }
  }
 for (;i<N_SECTIONS;i++)
  { if (sections[i].name[0])
     { printf("mapped section %d (%.*s) above top_section\n",
					i,SEC_NAMLEN,sections[i].name);
     }
  }
 for (cml= &section_cmaps[0];cml;cml=cml->link)
  { cmap_map[cml-section_cmaps] ++;
  }
 proc_map[0] ++;
 r = &section_procs[0];
 for (pl=r->flink;pl!=r;pl=pl->flink)
  { proc_map[pl-section_procs] ++;
  }
 for (i=0;i<CMAP_LIST_SIZE;i++)
  { if (cmap_map[i] != 1)
     { printf("cmap entry %d: count %d\n",cmap_map[i]);
     }
  }
 for (i=0;i<PROC_LIST_SIZE;i++)
  { if (proc_map[i] != 1)
     { printf("proc entry %d: count %d\n",proc_map[i]);
     }
  }
 wmemfree(cmap_map,CMAP_LIST_SIZE);
 wmemfree(proc_map,PROC_LIST_SIZE);
 section_unlock();
}

section_syscall_verbose()
{
 struct a {
   int verbose; } *uap = (struct a *) u.u_ap;

 section_verbose = !!uap->verbose;
 printf("section verbosity now %s\n",section_verbose?"on":"off");
}

syscall_memlock()
{
 struct a {
   caddr_t addr;
   int size; } *uap = (struct a *) u.u_ap;

 if (uap->size & CLOFSET)
  { u.u_error = EALIGN;
    return;
  }
 if (!claligned(uap->addr))
  { u.u_error = EALIGN;
    return;
  }
 if (!useracc(uap->addr,uap->size,B_READ))
  { u.u_error = EFAULT;
    return;
  }
 if (!isadsv(u.u_procp,btop(uap->addr)) &&
     !isatsv(u.u_procp,btop(uap->addr)) )
  { u.u_error = EINVAL;
    return;
  }
 if ( (isadsv(u.u_procp,btop(uap->addr+uap->size-1)) !=
       isadsv(u.u_procp,btop(uap->addr            )) ) ||
      (isatsv(u.u_procp,btop(uap->addr+uap->size-1)) !=
       isatsv(u.u_procp,btop(uap->addr            )) ) )
  { u.u_error = EINVAL;
    return;
  }
 if (section_verbose)
  { printf("proc %d memlock %d at %x\n",u.u_procp->p_pid,uap->size,uap->addr);
  }
 u.u_error = lock_memory(uap->addr,uap->size);
}

lock_memory(addr,size)
caddr_t addr;
int size;
{
 int i;
 int ncmaps;
 register int s;

 ncmaps = size / CLBYTES;
 s = splhigh();
 if (n_pages_locked+ncmaps > MAX_LOCKED_PAGES)
  { splx(s);
    if (section_verbose)
     { printf("n_pages_locked = %d, ncmaps = %d, MAX_LOCKED = %d\n",
				n_pages_locked,ncmaps,MAX_LOCKED_PAGES);
     }
    return(ETABLEFULL);
  }
 n_pages_locked += ncmaps;
 splx(s);
 u.u_procp->p_flag |= SULOCK;
 vslock(addr,size);
 for (i=0;i<ncmaps;i++)
  { register int pf;
    register struct cmap *cmp;
    pf = pgtocm(vtopte(u.u_procp,btop(addr+(i*CLBYTES)))->pg_pfnum);
    cmp = &cmap[pf];
    s = splhigh();
    if (! cmp->c_ulock)
     { n_pages_locked ++;
     }
    cmp->c_ulock = 1;
    cmp->c_refcnt ++;
    n_pages_locked --;
    splx(s);
  }
 vsunlock(addr,size);
 return(0);
}

syscall_memunlock()
{
 struct a {
   caddr_t addr;
   int size; } *uap = (struct a *) u.u_ap;
 register int i;
 register int ncmaps;

 if (uap->size & CLOFSET)
  { u.u_error = EALIGN;
    return;
  }
 if (!claligned(uap->addr))
  { u.u_error = EALIGN;
    return;
  }
 if (!useracc(uap->addr,uap->size,B_READ))
  { u.u_error = EFAULT;
    return;
  }
 if (!isadsv(u.u_procp,btop(uap->addr)) &&
     !isatsv(u.u_procp,btop(uap->addr)) )
  { u.u_error = EINVAL;
    return;
  }
 if ( (isadsv(u.u_procp,btop(uap->addr+uap->size-1)) !=
       isadsv(u.u_procp,btop(uap->addr            )) ) ||
      (isatsv(u.u_procp,btop(uap->addr+uap->size-1)) !=
       isatsv(u.u_procp,btop(uap->addr            )) ) )
  { u.u_error = EINVAL;
    return;
  }
 if (section_verbose)
  { printf("proc %d memunlock %d at %x\n",u.u_procp->p_pid,uap->size,uap->addr);
  }
 vslock(uap->addr,uap->size);
 ncmaps = uap->size / CLBYTES;
 for (i=0;i<ncmaps;i++)
  { register int pf = pgtocm(vtopte(u.u_procp,btop(uap->addr+(i*CLBYTES)))->pg_pfnum);
    if ((int)cmap[pf].c_refcnt > 0)
     { if (cmap[pf].c_ulock)
	{ register int s = splhigh();
	  n_pages_locked --;
	  splx(s);
	}
       cmap[pf].c_refcnt --;
       if (cmap[pf].c_refcnt == 0)
	{ cmap[pf].c_ulock = 0;
	}
     }
  }
 vsunlock(uap->addr,uap->size);
}

#endif
