Files
Arquivotheca.SunOS-4.1.4/sys/sun4m/spt.c
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

662 lines
14 KiB
C

/* @(#)spt.c 1.1 94/10/31 SMI */
#include <sys/param.h>
#include <sys/user.h>
#include <sys/mman.h>
#include <vm/hat.h>
#include <vm/seg.h>
#include <vm/as.h>
#include <vm/page.h>
#include <sun4m/mmu.h>
#include <sun4m/pte.h>
#include <sun4m/spt.h>
#ifdef MULTIPROCESSOR
#include <machine/async.h>
#include "percpu.h"
#endif MULTIPROCESSOR
#define SEGSPTADDR (addr_t)0x0
#define CHECK_MAXMEM(x) ((spt_used + (x)) * 100 < maxmem * spt_max)
static int spt_max = 90; /* max percent among maxmem for spt */
static u_int spt_used; /* # pages used for spt */
int spt_num = 6; /* maximal number of spt segments permitted */
struct spt_data **sptp = NULL; /* vector of sptp's */
extern int maxmem;
extern union ptpe percpu_ptpe[]; /* machdep.c */
int segspt_create(/* seg, argsp */);
int segspt_unmap(/* seg, raddr, ssize */);
int segspt_lockop(/* seg, raddr, ssize, func */);
int segspt_free(/* seg */);
int segspt_badops();
void segspt_free_pages();
struct seg_ops segspt_ops = {
segspt_badops,
segspt_unmap,
segspt_free,
segspt_badops,
segspt_badops,
segspt_badops,
segspt_badops,
segspt_badops,
segspt_badops,
(u_int (*)()) NULL, /* swapout */
segspt_badops,
segspt_badops,
segspt_lockop,
segspt_badops
};
int segspt_shmdup(/* seg, newseg */);
int segspt_shmunmap(/* seg, raddr, ssize */);
int segspt_shmfree(/* seg */);
faultcode_t segspt_shmfault();
int segspt_shmsetprot();
int segspt_shmcheckprot();
int segspt_shmbadops();
struct seg_ops segspt_shmops = {
segspt_shmdup,
segspt_shmunmap,
segspt_shmfree,
segspt_shmfault,
segspt_shmbadops,
segspt_shmbadops,
segspt_shmsetprot,
segspt_shmcheckprot,
segspt_shmbadops,
(u_int (*)()) NULL,
segspt_shmbadops,
segspt_shmbadops,
segspt_shmbadops,
segspt_shmbadops
} ;
struct spt_data *
sptcreate(size)
int size;
{
int err;
int i;
struct spt_data *spt;
struct as *as;
as = as_alloc(); /* in order to make 0x0 as the start addr */
/* To get special treatment in hat_setup() for spt
as->a_hat.hat_sv_uunix = (struct user *)&segspt_ops;
as->a_hat.hat_oncpu = cpuid | 8; */
spt = (struct spt_data *) kmem_zalloc(sizeof (struct spt_data));
spt->as = as;
if (sptp == NULL) {
/* create sptp area... */
sptp = (struct spt_data **)
kmem_zalloc((sizeof(struct spt_data *) * (spt_num + 1)));
sptp[0] = (struct spt_data *) spt_num;
} else {
/* verify sptp area */
if (sptp[0] != (struct spt_data *) spt_num) {
printf("sptcreate: resetting spt_num value\n");
spt_num = (int) sptp[0];
}
}
/* find free slot */
for(i = 1; i <= spt_num; i++) {
if (sptp[i] == NULL)
break;
}
if (i > spt_num) {
err = EAGAIN;
goto bad;
}
/* insert spt in free slot */
sptp[i] = spt;
if (err = as_map(as, SEGSPTADDR, size, segspt_create, (caddr_t) 0)) {
sptp[i] = NULL;
goto bad;
}
spt->refcnt = 1;
spt->size = size;
spt->anon = NULL;/* mark that shared page table is used */
#ifdef SUNDBE
printf("ISM segment created size 0x%x (=%d) bytes allocated.\n",
spt->size, spt->size);
#endif
return (spt);
bad:
as_free(as);
kmem_free((caddr_t) spt, sizeof (struct spt_data));
u.u_error = err;
return NULL;
}
#define L1_FREE 0
void
sptdestroy(spt)
struct spt_data *spt;
{
int s = splvm();
int i, cnt;
struct as *as = spt->as;
struct l1pt *l1pt = as->a_hat.hat_l1pt;
struct ptp *ptpp;
#ifdef SPT_DEBUG
printf("hat_oncpu = %d, cpuid = %d \n",
as->a_hat.hat_oncpu, cpuid);
#endif
#ifdef SUNDBE
printf("ISM segment destroyed size 0x%x (=%d) bytes freed.\n",
spt->size, spt->size);
#endif
if (sptp == NULL)
panic("sptdestroy: no sptp\n");
/* verify spt_num */
if (spt_num != (int) sptp[0]) {
printf("sptdestroy: resetting spt_num value\n");
spt_num = (int) sptp[0];
}
/* remove spt from array */
for (i = 1, cnt = 0; i <= spt_num; i++) {
if (sptp[i] == spt)
sptp[i] = NULL;
if (sptp[i] == NULL)
cnt++;
}
if (cnt == spt_num) { /* all entries empty, deallocate array */
kmem_free((caddr_t) sptp,
(sizeof(struct spt_data *) * (spt_num + 1)));
sptp = NULL;
}
/* Map the percpu area for this CPU.
* There is no u area for spt->as.
* So we have to hat_map_percpu by ourselves which was done in
* hat_map_percpu(&((struct seguser *)(as->a_hat.hat_sv_uunix))->segu_u);
*/
s = splvm();
ptpp = &(l1pt->ptpe[getl1in(VA_PERCPUME)].ptp);
stphys(va2pa((addr_t)ptpp), percpu_ptpe[cpuid].ptpe_int);
(void) splx(s);
as_unmap(as, SEGSPTADDR, spt->size);
/*as->a_segs = NULL; supposedly done in seg_free */
/* hat_l1free is done in as_free */
as_free(as);
kmem_free((caddr_t)spt, sizeof (struct spt_data));
}
/*
* called from seg_free().
* free (i.e., unlock, unmap, return to free list)
* all the pages in the given seg.
*/
int
segspt_free(seg)
struct seg *seg;
{
struct as *save = u.u_procp->p_as;
int sx;
#ifdef SPT_DEBUG
printf("segspt_free is called 1 \n");
#endif
sx = splvm();
hat_setup(seg->s_as);
#ifdef SPT_DEBUG
printf("segspt_free is called 2 \n");
#endif
(void)segspt_free_pages(seg, seg->s_base, seg->s_size);
#ifdef SPT_DEBUG
printf("segspt_free is called 3 \n");
#endif
hat_setup(save);
(void)splx(sx);
return 0;
}
/*
* called from as_ctl(, MC_LOCK,)
*
*/
int
segspt_lockop(seg, raddr, ssize, func)
struct seg *seg;
addr_t raddr;
u_int ssize;
int func;
{
/* for spt, as->a_paglck is never set
* so this routine should not be called.
*/
printf("segspt_lockop called \n");
}
int
segspt_unmap(seg, raddr, ssize)
struct seg *seg;
addr_t raddr;
u_int ssize;
{
#ifdef SPT_DEBUG
printf("segspt_unmap is called \n");
#endif
if (raddr == seg->s_base && ssize == seg->s_size) {
seg_free(seg);
return (0);
}
else
panic("segspt_unmap - unexpected address \n");
}
int
segspt_badops()
{
panic("segspt_badops is called");
}
int
segspt_create(seg, argsp)
struct seg *seg;
caddr_t argsp;
{
int err;
struct as *saveas = u.u_procp->p_as;
u_int len = seg->s_size;
addr_t addr = seg->s_base;
int sx;
sx = splvm();
hat_setup(seg->s_as); /* get an ctx */
err = segspt_alloc_map_pages(seg, addr, len);
if (err)
goto out;
seg->s_ops = &segspt_ops;
seg->s_data = (caddr_t) &segspt_ops; /* seg driver is attached */
bzero(addr, len); /* XXXX */
out:
hat_setup(saveas);
(void)splx(sx);
#ifdef SPT_DEBUG
printf("from segspt_create: allocation is done \n");
#endif
return(err);
}
int
segspt_alloc_map_pages(seg, addr, len)
struct seg *seg;
addr_t addr;
u_int len;
{
struct page *pp;
addr_t v;
#ifdef SPT_DEBUG
printf("segspt_alloc_map_pages \n");
#endif
if (!CHECK_MAXMEM(btopr(len)))
return (ENOMEM);
for (v = addr; v < addr + len; v += PAGESIZE) {
pp = page_get(PAGESIZE, 1); /* get a new page */
hat_setup(seg->s_as); /* maybe context has been changed ? */
if (pp == (struct page *)NULL) {
printf("page_get gets NULL page");
(void)segspt_free_pages(seg, addr, (u_int)(v - addr));
return (ENOMEM);
}
hat_memload(seg, v, pp, PROT_ALL, PTELD_LOCK);
/*page_sub(&pp, pp); */
}
spt_used += btopr(len);
return (0);
}
void
segspt_free_pages(seg, addr, len)
struct seg *seg;
addr_t addr;
u_int len;
{
union ptpe *ptpe;
struct page *pp;
int sx;
spt_used -= btopr(len);
sx = splhigh();
for (; (int)len > 0; len -= PAGESIZE, addr += PAGESIZE) {
ptpe = hat_ptefind(seg->s_as, addr);
pp = ptetopp(&ptpe->pte);
/* printf("before pp = %x \n", pp); */
if (pte_valid(&ptpe->pte))
hat_unlock_ptbl(ptetoptbl(&ptpe->pte));
else
panic("invalid pte in spt \n");
hat_unload(seg, addr, PAGESIZE);
/*printf("pp = %x \n", pp);*/
PAGE_RELE(pp);
}
(void)splx(sx);
}
int
segspt_shmattach(seg, argsp)
struct seg *seg;
caddr_t argsp;
{
int s;
struct spt_data *spt = (struct spt_data *) argsp;
struct l1pt *l1pt = spt->as->a_hat.hat_l1pt;
struct ptp *ptpp;
#ifdef SPT_DEBUG
printf("segspt_shmattach is called \n");
#endif
seg->s_ops = &segspt_shmops;
seg->s_data = argsp;
spt->refcnt++;
/* make the new u area known to other processor (per cpu area) */
/*if (spt->as->a_hat.hat_oncpu != (cpuid | 8)) {
#ifdef SPT_DEBUG
printf("hat_oncpu = %d, cpuid = %d \n",
spt->as->a_hat.hat_oncpu, cpuid);
#endif
hat_map_percpu(&((struct seguser *)(spt->as->a_hat.hat_sv_uunix))->segu_u);
} */
s = splvm();
ptpp = &(l1pt->ptpe[getl1in(VA_PERCPUME)].ptp);
stphys(va2pa((addr_t)ptpp), percpu_ptpe[cpuid].ptpe_int);
(void) splx(s);
share_pagetables(seg, spt->as->a_segs);
return 0;
}
#define L1PTSHIFT 24
share_pagetables(attachseg, sptseg)
struct seg *attachseg;
struct seg *sptseg;
{
struct as *as = attachseg->s_as;
caddr_t addr = attachseg->s_base;
u_int size = attachseg->s_size;
struct as *sptas = sptseg->s_as;
struct as *saveas = u.u_procp->p_as;
union ptpe a_ptpe, s_ptpe;
union ptpe *ptpa, *ptps;
unsigned l1ptpa, l1ptps;
int i;
#ifdef SPT_DEBUG
printf("share_pagetables: as = %x, sptseg->s_as = %x, saveas = %x \n",
as, sptseg->s_as, saveas);
#endif
hat_setup(as); /* take care of as_dup */
ptps = &s_ptpe;
ptpa = &a_ptpe;
for (l1ptps = va2pa((addr_t) sptas->a_hat.hat_l1pt),
i = 0,
l1ptpa = (va2pa((addr_t) as->a_hat.hat_l1pt) +
getl1in(addr) * sizeof (struct ptp));
i < ((size + L2PTOFFSET) >> L1PTSHIFT);
l1ptps += sizeof (struct ptp),
i++,
l1ptpa += sizeof (struct ptp) ){
ptps->ptpe_int = ldphys(l1ptps);
if (pte_entrytype(ptps->ptp) == MMU_ET_INVALID)
panic("invalid shared memory l1 ptp");
ptpa->ptpe_int = ldphys(l1ptpa);
if (pte_entrytype(ptpa->ptp) != MMU_ET_INVALID)
panic("already allocated shared memory l1 ptp");
stphys(l1ptpa, ptps->ptpe_int);
/* ptetoptbl(ptptopte(ptps->PageTablePointer))->lockcnt++;*/
}
hat_setup(saveas);
}
struct spt_data *
spt_lookup(as, addr)
struct as *as;
addr_t addr;
{
struct seg *seg;
#ifdef SPT_DEBUG
printf("spt_lookup is called \n");
#endif
if ((seg = as_segat(as, addr)) == NULL)
return(NULL);
if (seg->s_ops != &segspt_shmops)
return(NULL);
return((struct spt_data *)seg->s_data);
}
int
segspt_shmunmap(seg, raddr, ssize)
struct seg *seg;
addr_t raddr;
u_int ssize;
{
#ifdef SPT_DEBUG
printf("segspt_shmunmap is called \n");
#endif
unshare_pagetables(seg, raddr, ssize);
seg_free(seg);
return 0;
}
unshare_pagetables(seg, addr, size)
struct seg *seg;
addr_t addr;
u_int size;
{
int i;
struct as *as = seg->s_as;
unsigned l1ptp;
union ptpe a_ptp;
#ifdef SPT_DEBUG
union ptpe *ptpa;
ptpa = &a_ptp;
printf("unshare_pagetables is called \n");
#endif
for(i = 0,
l1ptp = va2pa((addr_t)as->a_hat.hat_l1pt) +
getl1in(addr) * sizeof (struct ptp);
i < ((size + L2PTOFFSET) >> L1PTSHIFT);
i++,
l1ptp += sizeof (struct ptp)) {
#ifdef SPT_DEBUG
ptpa->ptpe_int = ldphys(l1ptp);
if (pte_entrytype(ptpa->ptp) == MMU_ET_INVALID)
panic("unsharing invalid l1pte");
#endif
a_ptp.ptp.EntryType = MMU_ET_INVALID;
stphys(l1ptp, a_ptp.ptpe_int);
/* ptetoptbl(ptptopte(ptpa->PageTablePointer))->lockcnt--;*/
}
}
int
segspt_shmfree(seg)
struct seg *seg;
{
struct spt_data *spt;
#ifdef SPT_DEBUG
printf("segspt_shmfree is called \n");
#endif
spt = (struct spt_data *)seg->s_data;
--(spt->refcnt);
return 0;
}
int
segspt_shmsetprot()
{
printf("segspt_shmsetprot is called \n");
}
faultcode_t
segspt_shmfault(seg, addr, len, type, rw)
struct seg *seg;
addr_t addr;
u_int len;
enum fault_type type;
enum seg_rw rw;
{
struct seg *sptseg;
struct spt_data *spt;
union ptpe *ptpe;
struct pte pte;
struct ctx *ctx;
#ifdef SPT_DEBUG
printf("segspt_shmfault: ");
#endif
switch (type) {
case F_SOFTUNLOCK:
#ifdef SPT_DEBUG
printf("UNLOCK called \n");
#endif
return (0);
case F_SOFTLOCK:
return (0); /* Because we know that every shared memory is
* already locked
* and called in the same context.
*/
#ifdef SPT_DEBUG
ctx = seg->s_as->a_hat.hat_ctx;
if (ctx->c_num == mmu_getctx()) {
*(u_int *)&pte = mmu_probe(addr); /* faster than hat_ptefind */
printf("same context - use mmu_probe ");
if (pte_valid(&pte)) {
printf("pte valid \n");
return (0);
}
else
printf("invalid pte for mmu_probe \n");
}
else {
ptpe = hat_ptefind(seg->s_as, addr);
if (pte_valid(&ptpe->pte)) {
#ifdef SPT_DEBUG1
printf("SOFTLOCK: found addr = %x \n", addr);
#endif
return (0);
}
printf("using hat_ptefind due to different context\n");
}
#ifdef SPT_DEBUG1
printf("SOFTLOCK: not found addr = %x, seg = %x \n",
addr, seg);
#endif
#endif
case F_INVAL:
#ifdef SPT_DEBUG
printf("INVAL called \n");
#endif
spt = (struct spt_data *)seg->s_data;
sptseg = as_segat(spt->as, SEGSPTADDR);
share_pagetables(seg, sptseg);
return(0);
case F_PROT:
#ifdef SPT_DEBUG
printf("PROT called");
#endif
default:
#ifdef SPT_DEBUG
printf("- reaching default \n");
#endif
return(FC_NOMAP);
}
}
int
segspt_shmbadops()
{
panic("segspt_shmbadops is called \n");
}
/*
* duplicate the shared page tables
*/
int
segspt_shmdup(seg, newseg)
struct seg *seg, *newseg;
{
struct spt_data *spt = (struct spt_data *)seg->s_data;
#ifdef SPT_DEBUG
printf("segspt_shmdup is called \n");
#endif
newseg->s_data = (caddr_t) spt;
newseg->s_ops = &segspt_shmops;
spt->refcnt++;
/* share_pagetables(newseg, spt->as->a_segs);*/
return 0;
}
int
segspt_shmcheckprot(seg, addr, size, prot)
{
return 0;
}