2011-03-30 12:46:40 +00:00
|
|
|
#include "u.h"
|
|
|
|
#include "../port/lib.h"
|
|
|
|
#include "mem.h"
|
|
|
|
#include "dat.h"
|
|
|
|
#include "fns.h"
|
|
|
|
#include "../port/error.h"
|
|
|
|
|
2014-06-22 13:12:45 +00:00
|
|
|
int imagereclaim(int);
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Attachable segment types
|
|
|
|
*/
|
|
|
|
static Physseg physseg[10] = {
|
|
|
|
{ SG_SHARED, "shared", 0, SEGMAXSIZE, 0, 0 },
|
|
|
|
{ SG_BSS, "memory", 0, SEGMAXSIZE, 0, 0 },
|
|
|
|
{ 0, 0, 0, 0, 0, 0 },
|
|
|
|
};
|
|
|
|
|
|
|
|
static Lock physseglock;
|
|
|
|
|
|
|
|
#define IHASHSIZE 64
|
|
|
|
#define ihash(s) imagealloc.hash[s%IHASHSIZE]
|
|
|
|
static struct Imagealloc
|
|
|
|
{
|
|
|
|
Lock;
|
2014-06-22 13:12:45 +00:00
|
|
|
Image *list;
|
2011-03-30 12:46:40 +00:00
|
|
|
Image *free;
|
|
|
|
Image *hash[IHASHSIZE];
|
|
|
|
QLock ireclaim; /* mutex on reclaiming free images */
|
|
|
|
}imagealloc;
|
|
|
|
|
|
|
|
Segment* (*_globalsegattach)(Proc*, char*);
|
|
|
|
|
|
|
|
void
|
|
|
|
initseg(void)
|
|
|
|
{
|
|
|
|
Image *i, *ie;
|
|
|
|
|
2014-06-22 13:12:45 +00:00
|
|
|
imagealloc.list = xalloc(conf.nimage*sizeof(Image));
|
|
|
|
if(imagealloc.list == nil)
|
2011-12-12 18:17:58 +00:00
|
|
|
panic("initseg: no memory for Image");
|
2014-06-22 13:12:45 +00:00
|
|
|
ie = &imagealloc.list[conf.nimage-1];
|
|
|
|
for(i = imagealloc.list; i < ie; i++)
|
2011-03-30 12:46:40 +00:00
|
|
|
i->next = i+1;
|
2014-06-22 13:12:45 +00:00
|
|
|
i->next = nil;
|
|
|
|
imagealloc.free = imagealloc.list;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Segment *
|
2014-01-19 23:47:55 +00:00
|
|
|
newseg(int type, uintptr base, ulong size)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
Segment *s;
|
|
|
|
int mapsize;
|
|
|
|
|
|
|
|
if(size > (SEGMAPSIZE*PTEPERTAB))
|
|
|
|
error(Enovmem);
|
|
|
|
|
2014-06-22 13:12:45 +00:00
|
|
|
s = malloc(sizeof(Segment));
|
|
|
|
if(s == nil)
|
|
|
|
error(Enomem);
|
2011-03-30 12:46:40 +00:00
|
|
|
s->ref = 1;
|
|
|
|
s->type = type;
|
|
|
|
s->base = base;
|
|
|
|
s->top = base+(size*BY2PG);
|
|
|
|
s->size = size;
|
|
|
|
s->sema.prev = &s->sema;
|
|
|
|
s->sema.next = &s->sema;
|
|
|
|
|
|
|
|
mapsize = ROUND(size, PTEPERTAB)/PTEPERTAB;
|
|
|
|
if(mapsize > nelem(s->ssegmap)){
|
2014-06-22 13:12:45 +00:00
|
|
|
s->map = malloc(mapsize*sizeof(Pte*));
|
|
|
|
if(s->map == nil){
|
|
|
|
free(s);
|
|
|
|
error(Enomem);
|
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
s->mapsize = mapsize;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
s->map = s->ssegmap;
|
|
|
|
s->mapsize = nelem(s->ssegmap);
|
|
|
|
}
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
putseg(Segment *s)
|
|
|
|
{
|
|
|
|
Pte **pp, **emap;
|
|
|
|
Image *i;
|
|
|
|
|
2014-06-22 13:12:45 +00:00
|
|
|
if(s == nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
i = s->image;
|
2014-06-22 13:12:45 +00:00
|
|
|
if(i != nil) {
|
2011-03-30 12:46:40 +00:00
|
|
|
lock(i);
|
2014-06-22 13:12:45 +00:00
|
|
|
if(decref(s) != 0){
|
|
|
|
unlock(i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(i->s == s)
|
|
|
|
i->s = nil;
|
2011-03-30 12:46:40 +00:00
|
|
|
unlock(i);
|
|
|
|
putimage(i);
|
2014-06-22 13:12:45 +00:00
|
|
|
} else if(decref(s) != 0)
|
|
|
|
return;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
emap = &s->map[s->mapsize];
|
|
|
|
for(pp = s->map; pp < emap; pp++)
|
2014-06-22 13:12:45 +00:00
|
|
|
if(*pp != nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
freepte(s, *pp);
|
|
|
|
|
|
|
|
if(s->map != s->ssegmap)
|
|
|
|
free(s->map);
|
2014-06-22 13:12:45 +00:00
|
|
|
if(s->profile != nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
free(s->profile);
|
2014-06-22 13:12:45 +00:00
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
free(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-01-19 23:47:55 +00:00
|
|
|
relocateseg(Segment *s, uintptr offset)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
Page **pg, *x;
|
|
|
|
Pte *pte, **p, **endpte;
|
|
|
|
|
|
|
|
endpte = &s->map[s->mapsize];
|
|
|
|
for(p = s->map; p < endpte; p++) {
|
2014-06-22 13:12:45 +00:00
|
|
|
if((pte = *p) == nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
continue;
|
|
|
|
for(pg = pte->first; pg <= pte->last; pg++) {
|
2014-06-22 13:12:45 +00:00
|
|
|
if((x = *pg) != nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
x->va += offset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Segment*
|
|
|
|
dupseg(Segment **seg, int segno, int share)
|
|
|
|
{
|
|
|
|
int i, size;
|
|
|
|
Pte *pte;
|
|
|
|
Segment *n, *s;
|
|
|
|
|
|
|
|
SET(n);
|
|
|
|
s = seg[segno];
|
|
|
|
|
2014-06-22 13:12:45 +00:00
|
|
|
qlock(s);
|
2011-03-30 12:46:40 +00:00
|
|
|
if(waserror()){
|
2014-06-22 13:12:45 +00:00
|
|
|
qunlock(s);
|
2011-03-30 12:46:40 +00:00
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
switch(s->type&SG_TYPE) {
|
|
|
|
case SG_TEXT: /* New segment shares pte set */
|
|
|
|
case SG_SHARED:
|
|
|
|
case SG_PHYSICAL:
|
|
|
|
goto sameseg;
|
|
|
|
|
|
|
|
case SG_STACK:
|
|
|
|
n = newseg(s->type, s->base, s->size);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SG_BSS: /* Just copy on write */
|
|
|
|
if(share)
|
|
|
|
goto sameseg;
|
|
|
|
n = newseg(s->type, s->base, s->size);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SG_DATA: /* Copy on write plus demand load info */
|
|
|
|
if(segno == TSEG){
|
2012-01-09 20:33:22 +00:00
|
|
|
n = data2txt(s);
|
2011-03-30 12:46:40 +00:00
|
|
|
poperror();
|
2014-06-22 13:12:45 +00:00
|
|
|
qunlock(s);
|
2012-01-09 20:33:22 +00:00
|
|
|
return n;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(share)
|
|
|
|
goto sameseg;
|
|
|
|
n = newseg(s->type, s->base, s->size);
|
|
|
|
|
|
|
|
incref(s->image);
|
|
|
|
n->image = s->image;
|
|
|
|
n->fstart = s->fstart;
|
|
|
|
n->flen = s->flen;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
size = s->mapsize;
|
|
|
|
for(i = 0; i < size; i++)
|
2014-06-22 13:12:45 +00:00
|
|
|
if((pte = s->map[i]) != nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
n->map[i] = ptecpy(pte);
|
|
|
|
|
|
|
|
n->flushme = s->flushme;
|
|
|
|
if(s->ref > 1)
|
|
|
|
procflushseg(s);
|
|
|
|
poperror();
|
2014-06-22 13:12:45 +00:00
|
|
|
qunlock(s);
|
2011-03-30 12:46:40 +00:00
|
|
|
return n;
|
|
|
|
|
|
|
|
sameseg:
|
|
|
|
incref(s);
|
|
|
|
poperror();
|
2014-06-22 13:12:45 +00:00
|
|
|
qunlock(s);
|
2011-03-30 12:46:40 +00:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
segpage(Segment *s, Page *p)
|
|
|
|
{
|
|
|
|
Pte **pte;
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr off;
|
2011-03-30 12:46:40 +00:00
|
|
|
Page **pg;
|
|
|
|
|
|
|
|
if(p->va < s->base || p->va >= s->top)
|
|
|
|
panic("segpage");
|
|
|
|
|
|
|
|
off = p->va - s->base;
|
|
|
|
pte = &s->map[off/PTEMAPMEM];
|
2014-06-22 13:12:45 +00:00
|
|
|
if(*pte == nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
*pte = ptealloc();
|
|
|
|
|
|
|
|
pg = &(*pte)->pages[(off&(PTEMAPMEM-1))/BY2PG];
|
|
|
|
*pg = p;
|
|
|
|
if(pg < (*pte)->first)
|
|
|
|
(*pte)->first = pg;
|
|
|
|
if(pg > (*pte)->last)
|
|
|
|
(*pte)->last = pg;
|
|
|
|
}
|
|
|
|
|
|
|
|
Image*
|
2014-01-19 23:47:55 +00:00
|
|
|
attachimage(int type, Chan *c, uintptr base, ulong len)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
Image *i, **l;
|
|
|
|
|
|
|
|
lock(&imagealloc);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Search the image cache for remains of the text from a previous
|
|
|
|
* or currently running incarnation
|
|
|
|
*/
|
|
|
|
for(i = ihash(c->qid.path); i; i = i->hash) {
|
|
|
|
if(c->qid.path == i->qid.path) {
|
|
|
|
lock(i);
|
2013-11-08 21:31:26 +00:00
|
|
|
if(eqchantdqid(c, i->type, i->dev, i->qid, 0) && c->qid.type == i->qid.type)
|
2011-03-30 12:46:40 +00:00
|
|
|
goto found;
|
|
|
|
unlock(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-22 13:12:45 +00:00
|
|
|
/* dump pages of inactive images to free image structures */
|
|
|
|
while((i = imagealloc.free) == nil) {
|
2011-03-30 12:46:40 +00:00
|
|
|
unlock(&imagealloc);
|
2014-07-11 01:57:21 +00:00
|
|
|
if(imagereclaim(1000) == 0 && imagealloc.free == nil){
|
2013-05-26 23:04:53 +00:00
|
|
|
freebroken(); /* can use the memory */
|
|
|
|
resrcwait("no image after reclaim");
|
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
lock(&imagealloc);
|
|
|
|
}
|
|
|
|
|
|
|
|
imagealloc.free = i->next;
|
|
|
|
|
|
|
|
lock(i);
|
|
|
|
i->type = c->type;
|
2013-11-08 21:31:26 +00:00
|
|
|
i->dev = c->dev;
|
2011-03-30 12:46:40 +00:00
|
|
|
i->qid = c->qid;
|
2013-11-08 21:31:26 +00:00
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
l = &ihash(c->qid.path);
|
|
|
|
i->hash = *l;
|
|
|
|
*l = i;
|
2013-11-08 21:31:26 +00:00
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
found:
|
2014-06-22 13:12:45 +00:00
|
|
|
unlock(&imagealloc);
|
2013-11-08 21:31:26 +00:00
|
|
|
if(i->c == nil){
|
|
|
|
i->c = c;
|
|
|
|
c->flag &= ~CCACHE;
|
|
|
|
incref(c);
|
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2014-06-22 13:12:45 +00:00
|
|
|
if(i->s == nil) {
|
|
|
|
incref(i);
|
2011-03-30 12:46:40 +00:00
|
|
|
if(waserror()) {
|
|
|
|
unlock(i);
|
2012-10-14 17:48:46 +00:00
|
|
|
putimage(i);
|
|
|
|
nexterror();
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
i->s = newseg(type, base, len);
|
|
|
|
i->s->image = i;
|
|
|
|
poperror();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
incref(i->s);
|
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2014-06-22 13:12:45 +00:00
|
|
|
extern int pagereclaim(Image*, int); /* page.c */
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2014-06-22 13:12:45 +00:00
|
|
|
int
|
|
|
|
imagereclaim(int min)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2014-06-22 13:12:45 +00:00
|
|
|
static Image *i, *ie;
|
|
|
|
int j, n;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2014-06-22 13:12:45 +00:00
|
|
|
eqlock(&imagealloc.ireclaim);
|
|
|
|
if(i == nil){
|
|
|
|
i = imagealloc.list;
|
|
|
|
ie = &imagealloc.list[conf.nimage];
|
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
n = 0;
|
2014-06-22 13:12:45 +00:00
|
|
|
for(j = 0; j < conf.nimage; j++, i++){
|
|
|
|
if(i >= ie)
|
|
|
|
i = imagealloc.list;
|
|
|
|
if(i->ref == 0)
|
|
|
|
continue;
|
|
|
|
/*
|
|
|
|
* if there are no free image structures, only
|
|
|
|
* reclaim pages from inactive images.
|
|
|
|
*/
|
|
|
|
if(imagealloc.free != nil || i->ref == i->pgref){
|
|
|
|
n += pagereclaim(i, min - n);
|
|
|
|
if(n >= min)
|
|
|
|
break;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
qunlock(&imagealloc.ireclaim);
|
2014-06-22 13:12:45 +00:00
|
|
|
|
|
|
|
return n;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
putimage(Image *i)
|
|
|
|
{
|
|
|
|
Image *f, **l;
|
2012-10-10 06:22:35 +00:00
|
|
|
Chan *c;
|
2014-06-22 13:12:45 +00:00
|
|
|
int r;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2014-06-22 13:12:45 +00:00
|
|
|
if(i->notext){
|
|
|
|
decref(i);
|
2011-03-30 12:46:40 +00:00
|
|
|
return;
|
2014-06-22 13:12:45 +00:00
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2013-11-08 21:31:26 +00:00
|
|
|
c = nil;
|
2011-03-30 12:46:40 +00:00
|
|
|
lock(i);
|
2014-06-22 13:12:45 +00:00
|
|
|
r = decref(i);
|
|
|
|
if(r == i->pgref){
|
2013-11-08 21:31:26 +00:00
|
|
|
/*
|
|
|
|
* all remaining references to this image are from the
|
2014-06-22 13:12:45 +00:00
|
|
|
* page cache, so close the chan.
|
2013-11-08 21:31:26 +00:00
|
|
|
*/
|
|
|
|
c = i->c;
|
|
|
|
i->c = nil;
|
|
|
|
}
|
2014-06-22 13:12:45 +00:00
|
|
|
if(r == 0){
|
2011-03-30 12:46:40 +00:00
|
|
|
l = &ihash(i->qid.path);
|
|
|
|
mkqid(&i->qid, ~0, ~0, QTFILE);
|
|
|
|
unlock(i);
|
|
|
|
|
|
|
|
lock(&imagealloc);
|
2014-06-22 13:12:45 +00:00
|
|
|
for(f = *l; f != nil; f = f->hash) {
|
2011-03-30 12:46:40 +00:00
|
|
|
if(f == i) {
|
|
|
|
*l = i->hash;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
l = &f->hash;
|
|
|
|
}
|
|
|
|
i->next = imagealloc.free;
|
|
|
|
imagealloc.free = i;
|
|
|
|
unlock(&imagealloc);
|
2013-11-08 21:31:26 +00:00
|
|
|
} else
|
|
|
|
unlock(i);
|
2014-06-22 13:12:45 +00:00
|
|
|
if(c != nil)
|
2012-10-10 06:22:35 +00:00
|
|
|
ccloseq(c); /* does not block */
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
long
|
2014-01-19 23:47:55 +00:00
|
|
|
ibrk(uintptr addr, int seg)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
Segment *s, *ns;
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr newtop;
|
|
|
|
ulong newsize;
|
2011-03-30 12:46:40 +00:00
|
|
|
int i, mapsize;
|
|
|
|
Pte **map;
|
|
|
|
|
|
|
|
s = up->seg[seg];
|
2014-06-22 13:12:45 +00:00
|
|
|
if(s == nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
error(Ebadarg);
|
|
|
|
|
|
|
|
if(addr == 0)
|
|
|
|
return s->base;
|
|
|
|
|
2014-06-22 13:12:45 +00:00
|
|
|
qlock(s);
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
/* We may start with the bss overlapping the data */
|
|
|
|
if(addr < s->base) {
|
2014-06-22 13:12:45 +00:00
|
|
|
if(seg != BSEG || up->seg[DSEG] == nil || addr < up->seg[DSEG]->base) {
|
|
|
|
qunlock(s);
|
2011-03-30 12:46:40 +00:00
|
|
|
error(Enovmem);
|
|
|
|
}
|
|
|
|
addr = s->base;
|
|
|
|
}
|
|
|
|
|
|
|
|
newtop = PGROUND(addr);
|
|
|
|
newsize = (newtop-s->base)/BY2PG;
|
|
|
|
if(newtop < s->top) {
|
|
|
|
/*
|
|
|
|
* do not shrink a segment shared with other procs, as the
|
|
|
|
* to-be-freed address space may have been passed to the kernel
|
|
|
|
* already by another proc and is past the validaddr stage.
|
|
|
|
*/
|
|
|
|
if(s->ref > 1){
|
2014-06-22 13:12:45 +00:00
|
|
|
qunlock(s);
|
2011-03-30 12:46:40 +00:00
|
|
|
error(Einuse);
|
|
|
|
}
|
|
|
|
mfreeseg(s, newtop, (s->top-newtop)/BY2PG);
|
|
|
|
s->top = newtop;
|
|
|
|
s->size = newsize;
|
2014-06-22 13:12:45 +00:00
|
|
|
qunlock(s);
|
2011-03-30 12:46:40 +00:00
|
|
|
flushmmu();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(i = 0; i < NSEG; i++) {
|
|
|
|
ns = up->seg[i];
|
2014-06-22 13:12:45 +00:00
|
|
|
if(ns == nil || ns == s)
|
2011-03-30 12:46:40 +00:00
|
|
|
continue;
|
|
|
|
if(newtop >= ns->base && newtop < ns->top) {
|
2014-06-22 13:12:45 +00:00
|
|
|
qunlock(s);
|
2011-03-30 12:46:40 +00:00
|
|
|
error(Esoverlap);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(newsize > (SEGMAPSIZE*PTEPERTAB)) {
|
2014-06-22 13:12:45 +00:00
|
|
|
qunlock(s);
|
2011-03-30 12:46:40 +00:00
|
|
|
error(Enovmem);
|
|
|
|
}
|
|
|
|
mapsize = ROUND(newsize, PTEPERTAB)/PTEPERTAB;
|
|
|
|
if(mapsize > s->mapsize){
|
|
|
|
map = smalloc(mapsize*sizeof(Pte*));
|
|
|
|
memmove(map, s->map, s->mapsize*sizeof(Pte*));
|
|
|
|
if(s->map != s->ssegmap)
|
|
|
|
free(s->map);
|
|
|
|
s->map = map;
|
|
|
|
s->mapsize = mapsize;
|
|
|
|
}
|
|
|
|
|
|
|
|
s->top = newtop;
|
|
|
|
s->size = newsize;
|
2014-06-22 13:12:45 +00:00
|
|
|
qunlock(s);
|
2011-03-30 12:46:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-08-26 02:47:34 +00:00
|
|
|
/*
|
2014-06-22 13:12:45 +00:00
|
|
|
* called with s locked
|
2011-08-26 02:47:34 +00:00
|
|
|
*/
|
2014-07-14 04:02:21 +00:00
|
|
|
ulong
|
2011-08-26 02:47:34 +00:00
|
|
|
mcountseg(Segment *s)
|
|
|
|
{
|
2014-07-14 04:02:21 +00:00
|
|
|
ulong pages;
|
|
|
|
int i, j;
|
2014-06-22 13:12:45 +00:00
|
|
|
Page *pg;
|
2011-08-26 02:47:34 +00:00
|
|
|
|
|
|
|
pages = 0;
|
|
|
|
for(i = 0; i < s->mapsize; i++){
|
2014-06-22 13:12:45 +00:00
|
|
|
if(s->map[i] == nil)
|
2011-08-26 02:47:34 +00:00
|
|
|
continue;
|
2014-06-22 13:12:45 +00:00
|
|
|
for(j = 0; j < PTEPERTAB; j++){
|
|
|
|
pg = s->map[i]->pages[j];
|
|
|
|
if(!pagedout(pg))
|
2011-08-26 02:47:34 +00:00
|
|
|
pages++;
|
2014-06-22 13:12:45 +00:00
|
|
|
}
|
2011-08-26 02:47:34 +00:00
|
|
|
}
|
|
|
|
return pages;
|
|
|
|
}
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
/*
|
2014-06-22 13:12:45 +00:00
|
|
|
* called with s locked
|
2011-03-30 12:46:40 +00:00
|
|
|
*/
|
|
|
|
void
|
2014-01-19 23:47:55 +00:00
|
|
|
mfreeseg(Segment *s, uintptr start, int pages)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
int i, j, size;
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr soff;
|
2011-03-30 12:46:40 +00:00
|
|
|
Page *pg;
|
2014-06-22 13:12:45 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We want to zero s->map[i]->page[j] and putpage(pg),
|
|
|
|
* but we have to make sure other processors flush the
|
|
|
|
* entry from their TLBs before the page is freed.
|
|
|
|
*/
|
|
|
|
if(s->ref > 1)
|
|
|
|
procflushseg(s);
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
soff = start-s->base;
|
|
|
|
j = (soff&(PTEMAPMEM-1))/BY2PG;
|
|
|
|
|
|
|
|
size = s->mapsize;
|
|
|
|
for(i = soff/PTEMAPMEM; i < size; i++) {
|
|
|
|
if(pages <= 0)
|
2014-06-22 13:12:45 +00:00
|
|
|
return;
|
|
|
|
if(s->map[i] == nil) {
|
2011-03-30 12:46:40 +00:00
|
|
|
pages -= PTEPERTAB-j;
|
|
|
|
j = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
while(j < PTEPERTAB) {
|
|
|
|
pg = s->map[i]->pages[j];
|
2014-06-22 13:12:45 +00:00
|
|
|
if(pg != nil){
|
|
|
|
s->map[i]->pages[j] = nil;
|
|
|
|
putpage(pg);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
if(--pages == 0)
|
2014-06-22 13:12:45 +00:00
|
|
|
return;
|
2011-03-30 12:46:40 +00:00
|
|
|
j++;
|
|
|
|
}
|
|
|
|
j = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Segment*
|
2014-03-04 21:37:15 +00:00
|
|
|
isoverlap(Proc *p, uintptr va, uintptr len)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
Segment *ns;
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr newtop;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
newtop = va+len;
|
|
|
|
for(i = 0; i < NSEG; i++) {
|
|
|
|
ns = p->seg[i];
|
2014-06-22 13:12:45 +00:00
|
|
|
if(ns == nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
continue;
|
|
|
|
if((newtop > ns->base && newtop <= ns->top) ||
|
|
|
|
(va >= ns->base && va < ns->top))
|
|
|
|
return ns;
|
|
|
|
}
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
addphysseg(Physseg* new)
|
|
|
|
{
|
|
|
|
Physseg *ps;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check not already entered and there is room
|
|
|
|
* for a new entry and the terminating null entry.
|
|
|
|
*/
|
|
|
|
lock(&physseglock);
|
|
|
|
for(ps = physseg; ps->name; ps++){
|
|
|
|
if(strcmp(ps->name, new->name) == 0){
|
|
|
|
unlock(&physseglock);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(ps-physseg >= nelem(physseg)-2){
|
|
|
|
unlock(&physseglock);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
*ps = *new;
|
|
|
|
unlock(&physseglock);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
isphysseg(char *name)
|
|
|
|
{
|
|
|
|
Physseg *ps;
|
|
|
|
int rv = 0;
|
|
|
|
|
|
|
|
lock(&physseglock);
|
|
|
|
for(ps = physseg; ps->name; ps++){
|
|
|
|
if(strcmp(ps->name, name) == 0){
|
|
|
|
rv = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
unlock(&physseglock);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr
|
2014-03-04 21:37:15 +00:00
|
|
|
segattach(Proc *p, ulong attr, char *name, uintptr va, uintptr len)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
int sno;
|
|
|
|
Segment *s, *os;
|
|
|
|
Physseg *ps;
|
|
|
|
|
|
|
|
if(va != 0 && va >= USTKTOP)
|
|
|
|
error(Ebadarg);
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
validaddr((uintptr)name, 1, 0);
|
2011-03-30 12:46:40 +00:00
|
|
|
vmemchr(name, 0, ~0);
|
|
|
|
|
|
|
|
for(sno = 0; sno < NSEG; sno++)
|
|
|
|
if(p->seg[sno] == nil && sno != ESEG)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if(sno == NSEG)
|
|
|
|
error(Enovmem);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* first look for a global segment with the
|
|
|
|
* same name
|
|
|
|
*/
|
|
|
|
if(_globalsegattach != nil){
|
|
|
|
s = (*_globalsegattach)(p, name);
|
|
|
|
if(s != nil){
|
|
|
|
p->seg[sno] = s;
|
|
|
|
return s->base;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-14 14:04:22 +00:00
|
|
|
/* round up va+len */
|
|
|
|
len += va & (BY2PG-1);
|
2011-03-30 12:46:40 +00:00
|
|
|
len = PGROUND(len);
|
2014-09-14 14:04:22 +00:00
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
if(len == 0)
|
|
|
|
error(Ebadarg);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find a hole in the address space.
|
|
|
|
* Starting at the lowest possible stack address - len,
|
|
|
|
* check for an overlapping segment, and repeat at the
|
|
|
|
* base of that segment - len until either a hole is found
|
|
|
|
* or the address space is exhausted. Ensure that we don't
|
|
|
|
* map the zero page.
|
|
|
|
*/
|
|
|
|
if(va == 0) {
|
|
|
|
for (os = p->seg[SSEG]; os != nil; os = isoverlap(p, va, len)) {
|
|
|
|
va = os->base;
|
|
|
|
if(len >= va)
|
|
|
|
error(Enovmem);
|
|
|
|
va -= len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-04 21:37:15 +00:00
|
|
|
va &= ~(BY2PG-1);
|
|
|
|
if(va == 0 || (va+len) > USTKTOP || (va+len) < va)
|
|
|
|
error(Ebadarg);
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
if(isoverlap(p, va, len) != nil)
|
|
|
|
error(Esoverlap);
|
|
|
|
|
|
|
|
for(ps = physseg; ps->name; ps++)
|
|
|
|
if(strcmp(name, ps->name) == 0)
|
|
|
|
goto found;
|
|
|
|
|
|
|
|
error(Ebadarg);
|
|
|
|
found:
|
|
|
|
if(len > ps->size)
|
|
|
|
error(Enovmem);
|
|
|
|
|
|
|
|
attr &= ~SG_TYPE; /* Turn off what is not allowed */
|
|
|
|
attr |= ps->attr; /* Copy in defaults */
|
|
|
|
|
|
|
|
s = newseg(attr, va, len/BY2PG);
|
|
|
|
s->pseg = ps;
|
|
|
|
p->seg[sno] = s;
|
|
|
|
|
|
|
|
return va;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
pteflush(Pte *pte, int s, int e)
|
|
|
|
{
|
2014-06-22 13:12:45 +00:00
|
|
|
Page *pg;
|
2011-03-30 12:46:40 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for(i = s; i < e; i++) {
|
2014-06-22 13:12:45 +00:00
|
|
|
pg = pte->pages[i];
|
|
|
|
if(!pagedout(pg))
|
2015-02-07 01:52:23 +00:00
|
|
|
pg->txtflush = ~0;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr
|
|
|
|
syssegflush(va_list list)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
Segment *s;
|
2014-02-02 08:59:54 +00:00
|
|
|
ulong len, chunk, l;
|
2011-03-30 12:46:40 +00:00
|
|
|
Pte *pte;
|
2014-02-02 08:59:54 +00:00
|
|
|
uintptr ps, pe, addr;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
addr = va_arg(list, uintptr);
|
|
|
|
len = va_arg(list, ulong);
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
while(len > 0) {
|
|
|
|
s = seg(up, addr, 1);
|
|
|
|
if(s == 0)
|
|
|
|
error(Ebadarg);
|
|
|
|
|
|
|
|
s->flushme = 1;
|
|
|
|
more:
|
|
|
|
l = len;
|
|
|
|
if(addr+l > s->top)
|
|
|
|
l = s->top - addr;
|
|
|
|
|
|
|
|
ps = addr-s->base;
|
|
|
|
pte = s->map[ps/PTEMAPMEM];
|
|
|
|
ps &= PTEMAPMEM-1;
|
|
|
|
pe = PTEMAPMEM;
|
|
|
|
if(pe-ps > l){
|
|
|
|
pe = ps + l;
|
2014-02-02 08:59:54 +00:00
|
|
|
pe = PGROUND(pe);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
if(pe == ps) {
|
2014-06-22 13:12:45 +00:00
|
|
|
qunlock(s);
|
2011-03-30 12:46:40 +00:00
|
|
|
error(Ebadarg);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(pte)
|
|
|
|
pteflush(pte, ps/BY2PG, pe/BY2PG);
|
|
|
|
|
|
|
|
chunk = pe-ps;
|
|
|
|
len -= chunk;
|
|
|
|
addr += chunk;
|
|
|
|
|
|
|
|
if(len > 0 && addr < s->top)
|
|
|
|
goto more;
|
|
|
|
|
2014-06-22 13:12:45 +00:00
|
|
|
qunlock(s);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
flushmmu();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-01-19 23:47:55 +00:00
|
|
|
segclock(uintptr pc)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
Segment *s;
|
|
|
|
|
|
|
|
s = up->seg[TSEG];
|
2014-06-22 13:12:45 +00:00
|
|
|
if(s == nil || s->profile == nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
s->profile[0] += TK2MS(1);
|
|
|
|
if(pc >= s->base && pc < s->top) {
|
|
|
|
pc -= s->base;
|
|
|
|
s->profile[pc>>LRESPROF] += TK2MS(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-14 04:02:21 +00:00
|
|
|
Segment*
|
|
|
|
txt2data(Segment *s)
|
|
|
|
{
|
|
|
|
Segment *ps;
|
|
|
|
|
|
|
|
ps = newseg(SG_DATA, s->base, s->size);
|
|
|
|
ps->image = s->image;
|
|
|
|
incref(ps->image);
|
|
|
|
ps->fstart = s->fstart;
|
|
|
|
ps->flen = s->flen;
|
|
|
|
ps->flushme = 1;
|
|
|
|
qunlock(s);
|
|
|
|
putseg(s);
|
|
|
|
qlock(ps);
|
|
|
|
return ps;
|
|
|
|
}
|
|
|
|
|
|
|
|
Segment*
|
|
|
|
data2txt(Segment *s)
|
|
|
|
{
|
|
|
|
Segment *ps;
|
|
|
|
|
|
|
|
ps = newseg(SG_TEXT, s->base, s->size);
|
|
|
|
ps->image = s->image;
|
|
|
|
incref(ps->image);
|
|
|
|
ps->fstart = s->fstart;
|
|
|
|
ps->flen = s->flen;
|
|
|
|
ps->flushme = 1;
|
|
|
|
return ps;
|
|
|
|
}
|