13e12c5d1SDavid du Colombier #include "u.h" 23e12c5d1SDavid du Colombier #include "../port/lib.h" 33e12c5d1SDavid du Colombier #include "mem.h" 43e12c5d1SDavid du Colombier #include "dat.h" 53e12c5d1SDavid du Colombier #include "fns.h" 63e12c5d1SDavid du Colombier #include "../port/error.h" 73e12c5d1SDavid du Colombier 87dd7cddfSDavid du Colombier static void imagereclaim(void); 97dd7cddfSDavid du Colombier static void imagechanreclaim(void); 103e12c5d1SDavid du Colombier 11219b2ee8SDavid du Colombier #include "io.h" 129a747e4fSDavid du Colombier 139a747e4fSDavid du Colombier /* 149a747e4fSDavid du Colombier * Attachable segment types 159a747e4fSDavid du Colombier */ 169a747e4fSDavid du Colombier static Physseg physseg[10] = { 179a747e4fSDavid du Colombier { SG_SHARED, "shared", 0, SEGMAXSIZE, 0, 0 }, 189a747e4fSDavid du Colombier { SG_BSS, "memory", 0, SEGMAXSIZE, 0, 0 }, 199a747e4fSDavid du Colombier { 0, 0, 0, 0, 0, 0 }, 209a747e4fSDavid du Colombier }; 213e12c5d1SDavid du Colombier 227dd7cddfSDavid du Colombier static Lock physseglock; 237dd7cddfSDavid du Colombier 247dd7cddfSDavid du Colombier #define NFREECHAN 64 253e12c5d1SDavid du Colombier #define IHASHSIZE 64 263e12c5d1SDavid du Colombier #define ihash(s) imagealloc.hash[s%IHASHSIZE] 2759cc4ca5SDavid du Colombier static struct Imagealloc 283e12c5d1SDavid du Colombier { 293e12c5d1SDavid du Colombier Lock; 303e12c5d1SDavid du Colombier Image *free; 313e12c5d1SDavid du Colombier Image *hash[IHASHSIZE]; 327dd7cddfSDavid du Colombier QLock ireclaim; /* mutex on reclaiming free images */ 337dd7cddfSDavid du Colombier 347dd7cddfSDavid du Colombier Chan **freechan; /* free image channels */ 357dd7cddfSDavid du Colombier int nfreechan; /* number of free channels */ 367dd7cddfSDavid du Colombier int szfreechan; /* size of freechan array */ 377dd7cddfSDavid du Colombier QLock fcreclaim; /* mutex on reclaiming free channels */ 383e12c5d1SDavid du Colombier }imagealloc; 393e12c5d1SDavid du Colombier 409a747e4fSDavid du Colombier Segment* (*_globalsegattach)(Proc*, char*); 419a747e4fSDavid du Colombier 423e12c5d1SDavid du Colombier void 433e12c5d1SDavid du Colombier initseg(void) 443e12c5d1SDavid du Colombier { 453e12c5d1SDavid du Colombier Image *i, *ie; 463e12c5d1SDavid du Colombier 473e12c5d1SDavid du Colombier imagealloc.free = xalloc(conf.nimage*sizeof(Image)); 483e12c5d1SDavid du Colombier ie = &imagealloc.free[conf.nimage-1]; 493e12c5d1SDavid du Colombier for(i = imagealloc.free; i < ie; i++) 503e12c5d1SDavid du Colombier i->next = i+1; 513e12c5d1SDavid du Colombier i->next = 0; 527dd7cddfSDavid du Colombier imagealloc.freechan = malloc(NFREECHAN * sizeof(Chan*)); 537dd7cddfSDavid du Colombier imagealloc.szfreechan = NFREECHAN; 543e12c5d1SDavid du Colombier } 553e12c5d1SDavid du Colombier 563e12c5d1SDavid du Colombier Segment * 573e12c5d1SDavid du Colombier newseg(int type, ulong base, ulong size) 583e12c5d1SDavid du Colombier { 593e12c5d1SDavid du Colombier Segment *s; 607dd7cddfSDavid du Colombier int mapsize; 613e12c5d1SDavid du Colombier 623e12c5d1SDavid du Colombier if(size > (SEGMAPSIZE*PTEPERTAB)) 633e12c5d1SDavid du Colombier error(Enovmem); 643e12c5d1SDavid du Colombier 657dd7cddfSDavid du Colombier if(swapfull()) 667dd7cddfSDavid du Colombier error(Enoswap); 673e12c5d1SDavid du Colombier s = smalloc(sizeof(Segment)); 683e12c5d1SDavid du Colombier s->ref = 1; 693e12c5d1SDavid du Colombier s->type = type; 703e12c5d1SDavid du Colombier s->base = base; 713e12c5d1SDavid du Colombier s->top = base+(size*BY2PG); 723e12c5d1SDavid du Colombier s->size = size; 737dd7cddfSDavid du Colombier 747dd7cddfSDavid du Colombier mapsize = ROUND(size, PTEPERTAB)/PTEPERTAB; 757dd7cddfSDavid du Colombier if(mapsize > nelem(s->ssegmap)){ 767dd7cddfSDavid du Colombier mapsize *= 2; 777dd7cddfSDavid du Colombier if(mapsize > (SEGMAPSIZE*PTEPERTAB)) 787dd7cddfSDavid du Colombier mapsize = (SEGMAPSIZE*PTEPERTAB); 797dd7cddfSDavid du Colombier s->map = smalloc(mapsize*sizeof(Pte*)); 807dd7cddfSDavid du Colombier s->mapsize = mapsize; 817dd7cddfSDavid du Colombier } 827dd7cddfSDavid du Colombier else{ 837dd7cddfSDavid du Colombier s->map = s->ssegmap; 847dd7cddfSDavid du Colombier s->mapsize = nelem(s->ssegmap); 857dd7cddfSDavid du Colombier } 867dd7cddfSDavid du Colombier 873e12c5d1SDavid du Colombier return s; 883e12c5d1SDavid du Colombier } 893e12c5d1SDavid du Colombier 903e12c5d1SDavid du Colombier void 913e12c5d1SDavid du Colombier putseg(Segment *s) 923e12c5d1SDavid du Colombier { 933e12c5d1SDavid du Colombier Pte **pp, **emap; 943e12c5d1SDavid du Colombier Image *i; 953e12c5d1SDavid du Colombier 963e12c5d1SDavid du Colombier if(s == 0) 973e12c5d1SDavid du Colombier return; 983e12c5d1SDavid du Colombier 993e12c5d1SDavid du Colombier i = s->image; 100219b2ee8SDavid du Colombier if(i != 0) { 1013e12c5d1SDavid du Colombier lock(i); 102219b2ee8SDavid du Colombier lock(s); 103219b2ee8SDavid du Colombier if(i->s == s && s->ref == 1) 1043e12c5d1SDavid du Colombier i->s = 0; 1053e12c5d1SDavid du Colombier unlock(i); 1063e12c5d1SDavid du Colombier } 107219b2ee8SDavid du Colombier else 108219b2ee8SDavid du Colombier lock(s); 1093e12c5d1SDavid du Colombier 110219b2ee8SDavid du Colombier s->ref--; 111219b2ee8SDavid du Colombier if(s->ref != 0) { 112219b2ee8SDavid du Colombier unlock(s); 113219b2ee8SDavid du Colombier return; 114219b2ee8SDavid du Colombier } 1159a747e4fSDavid du Colombier unlock(s); 116219b2ee8SDavid du Colombier 1173e12c5d1SDavid du Colombier qlock(&s->lk); 1183e12c5d1SDavid du Colombier if(i) 1193e12c5d1SDavid du Colombier putimage(i); 1203e12c5d1SDavid du Colombier 1217dd7cddfSDavid du Colombier emap = &s->map[s->mapsize]; 1223e12c5d1SDavid du Colombier for(pp = s->map; pp < emap; pp++) 1233e12c5d1SDavid du Colombier if(*pp) 1243e12c5d1SDavid du Colombier freepte(s, *pp); 1253e12c5d1SDavid du Colombier 1263e12c5d1SDavid du Colombier qunlock(&s->lk); 1277dd7cddfSDavid du Colombier if(s->map != s->ssegmap) 1287dd7cddfSDavid du Colombier free(s->map); 1297dd7cddfSDavid du Colombier if(s->profile != 0) 1307dd7cddfSDavid du Colombier free(s->profile); 1313e12c5d1SDavid du Colombier free(s); 1323e12c5d1SDavid du Colombier } 1333e12c5d1SDavid du Colombier 1343e12c5d1SDavid du Colombier void 1353e12c5d1SDavid du Colombier relocateseg(Segment *s, ulong offset) 1363e12c5d1SDavid du Colombier { 1377dd7cddfSDavid du Colombier Page **pg, *x; 1387dd7cddfSDavid du Colombier Pte *pte, **p, **endpte; 1393e12c5d1SDavid du Colombier 1407dd7cddfSDavid du Colombier endpte = &s->map[s->mapsize]; 1413e12c5d1SDavid du Colombier for(p = s->map; p < endpte; p++) { 1427dd7cddfSDavid du Colombier if(*p == 0) 1437dd7cddfSDavid du Colombier continue; 1447dd7cddfSDavid du Colombier pte = *p; 1457dd7cddfSDavid du Colombier for(pg = pte->first; pg <= pte->last; pg++) { 1467dd7cddfSDavid du Colombier if(x = *pg) 1477dd7cddfSDavid du Colombier x->va += offset; 1483e12c5d1SDavid du Colombier } 1493e12c5d1SDavid du Colombier } 1503e12c5d1SDavid du Colombier } 1513e12c5d1SDavid du Colombier 1523e12c5d1SDavid du Colombier Segment* 153bd389b36SDavid du Colombier dupseg(Segment **seg, int segno, int share) 1543e12c5d1SDavid du Colombier { 1557dd7cddfSDavid du Colombier int i, size; 1563e12c5d1SDavid du Colombier Pte *pte; 157bd389b36SDavid du Colombier Segment *n, *s; 1583e12c5d1SDavid du Colombier 1593e12c5d1SDavid du Colombier SET(n); 160bd389b36SDavid du Colombier s = seg[segno]; 161bd389b36SDavid du Colombier 16280ee5cbfSDavid du Colombier qlock(&s->lk); 16380ee5cbfSDavid du Colombier if(waserror()){ 16480ee5cbfSDavid du Colombier qunlock(&s->lk); 16580ee5cbfSDavid du Colombier nexterror(); 16680ee5cbfSDavid du Colombier } 1673e12c5d1SDavid du Colombier switch(s->type&SG_TYPE) { 1683e12c5d1SDavid du Colombier case SG_TEXT: /* New segment shares pte set */ 1693e12c5d1SDavid du Colombier case SG_SHARED: 1703e12c5d1SDavid du Colombier case SG_PHYSICAL: 17180ee5cbfSDavid du Colombier goto sameseg; 1723e12c5d1SDavid du Colombier 1733e12c5d1SDavid du Colombier case SG_STACK: 1743e12c5d1SDavid du Colombier n = newseg(s->type, s->base, s->size); 1753e12c5d1SDavid du Colombier break; 1763e12c5d1SDavid du Colombier 1773e12c5d1SDavid du Colombier case SG_BSS: /* Just copy on write */ 1789a747e4fSDavid du Colombier if(share) 17980ee5cbfSDavid du Colombier goto sameseg; 1803e12c5d1SDavid du Colombier n = newseg(s->type, s->base, s->size); 1813e12c5d1SDavid du Colombier break; 1823e12c5d1SDavid du Colombier 1833e12c5d1SDavid du Colombier case SG_DATA: /* Copy on write plus demand load info */ 18480ee5cbfSDavid du Colombier if(segno == TSEG){ 18580ee5cbfSDavid du Colombier poperror(); 18680ee5cbfSDavid du Colombier qunlock(&s->lk); 187bd389b36SDavid du Colombier return data2txt(s); 1883e12c5d1SDavid du Colombier } 18980ee5cbfSDavid du Colombier 1909a747e4fSDavid du Colombier if(share) 19180ee5cbfSDavid du Colombier goto sameseg; 1923e12c5d1SDavid du Colombier n = newseg(s->type, s->base, s->size); 1933e12c5d1SDavid du Colombier 1943e12c5d1SDavid du Colombier incref(s->image); 1953e12c5d1SDavid du Colombier n->image = s->image; 1963e12c5d1SDavid du Colombier n->fstart = s->fstart; 1973e12c5d1SDavid du Colombier n->flen = s->flen; 1983e12c5d1SDavid du Colombier break; 1993e12c5d1SDavid du Colombier } 2007dd7cddfSDavid du Colombier size = s->mapsize; 2017dd7cddfSDavid du Colombier for(i = 0; i < size; i++) 2023e12c5d1SDavid du Colombier if(pte = s->map[i]) 2033e12c5d1SDavid du Colombier n->map[i] = ptecpy(pte); 2043e12c5d1SDavid du Colombier 2053e12c5d1SDavid du Colombier n->flushme = s->flushme; 2069a747e4fSDavid du Colombier if(s->ref > 1) 2079a747e4fSDavid du Colombier procflushseg(s); 20880ee5cbfSDavid du Colombier poperror(); 2093e12c5d1SDavid du Colombier qunlock(&s->lk); 2103e12c5d1SDavid du Colombier return n; 21180ee5cbfSDavid du Colombier 21280ee5cbfSDavid du Colombier sameseg: 21380ee5cbfSDavid du Colombier incref(s); 21480ee5cbfSDavid du Colombier poperror(); 21580ee5cbfSDavid du Colombier qunlock(&s->lk); 21680ee5cbfSDavid du Colombier return s; 2173e12c5d1SDavid du Colombier } 2183e12c5d1SDavid du Colombier 2193e12c5d1SDavid du Colombier void 2203e12c5d1SDavid du Colombier segpage(Segment *s, Page *p) 2213e12c5d1SDavid du Colombier { 2223e12c5d1SDavid du Colombier Pte **pte; 2233e12c5d1SDavid du Colombier ulong off; 2243e12c5d1SDavid du Colombier Page **pg; 2253e12c5d1SDavid du Colombier 2263e12c5d1SDavid du Colombier if(p->va < s->base || p->va >= s->top) 2273e12c5d1SDavid du Colombier panic("segpage"); 2283e12c5d1SDavid du Colombier 2293e12c5d1SDavid du Colombier off = p->va - s->base; 2303e12c5d1SDavid du Colombier pte = &s->map[off/PTEMAPMEM]; 2313e12c5d1SDavid du Colombier if(*pte == 0) 2323e12c5d1SDavid du Colombier *pte = ptealloc(); 2333e12c5d1SDavid du Colombier 2343e12c5d1SDavid du Colombier pg = &(*pte)->pages[(off&(PTEMAPMEM-1))/BY2PG]; 2353e12c5d1SDavid du Colombier *pg = p; 2363e12c5d1SDavid du Colombier if(pg < (*pte)->first) 2373e12c5d1SDavid du Colombier (*pte)->first = pg; 2383e12c5d1SDavid du Colombier if(pg > (*pte)->last) 2393e12c5d1SDavid du Colombier (*pte)->last = pg; 2403e12c5d1SDavid du Colombier } 2413e12c5d1SDavid du Colombier 2423e12c5d1SDavid du Colombier Image* 2433e12c5d1SDavid du Colombier attachimage(int type, Chan *c, ulong base, ulong len) 2443e12c5d1SDavid du Colombier { 2453e12c5d1SDavid du Colombier Image *i, **l; 2463e12c5d1SDavid du Colombier 2477dd7cddfSDavid du Colombier /* reclaim any free channels from reclaimed segments */ 2487dd7cddfSDavid du Colombier if(imagealloc.nfreechan) 2497dd7cddfSDavid du Colombier imagechanreclaim(); 2507dd7cddfSDavid du Colombier 2513e12c5d1SDavid du Colombier lock(&imagealloc); 2523e12c5d1SDavid du Colombier 2533e12c5d1SDavid du Colombier /* 2543e12c5d1SDavid du Colombier * Search the image cache for remains of the text from a previous 2553e12c5d1SDavid du Colombier * or currently running incarnation 2563e12c5d1SDavid du Colombier */ 2573e12c5d1SDavid du Colombier for(i = ihash(c->qid.path); i; i = i->hash) { 2583e12c5d1SDavid du Colombier if(c->qid.path == i->qid.path) { 2593e12c5d1SDavid du Colombier lock(i); 2603e12c5d1SDavid du Colombier if(eqqid(c->qid, i->qid) && 2613e12c5d1SDavid du Colombier eqqid(c->mqid, i->mqid) && 2623e12c5d1SDavid du Colombier c->mchan == i->mchan && 2633e12c5d1SDavid du Colombier c->type == i->type) { 2643e12c5d1SDavid du Colombier goto found; 2653e12c5d1SDavid du Colombier } 2663e12c5d1SDavid du Colombier unlock(i); 2673e12c5d1SDavid du Colombier } 2683e12c5d1SDavid du Colombier } 2693e12c5d1SDavid du Colombier 2703e12c5d1SDavid du Colombier /* 2713e12c5d1SDavid du Colombier * imagereclaim dumps pages from the free list which are cached by image 2723e12c5d1SDavid du Colombier * structures. This should free some image structures. 2733e12c5d1SDavid du Colombier */ 2743e12c5d1SDavid du Colombier while(!(i = imagealloc.free)) { 2753e12c5d1SDavid du Colombier unlock(&imagealloc); 2763e12c5d1SDavid du Colombier imagereclaim(); 2777dd7cddfSDavid du Colombier sched(); 2783e12c5d1SDavid du Colombier lock(&imagealloc); 2793e12c5d1SDavid du Colombier } 2803e12c5d1SDavid du Colombier 2813e12c5d1SDavid du Colombier imagealloc.free = i->next; 2823e12c5d1SDavid du Colombier 2833e12c5d1SDavid du Colombier lock(i); 2843e12c5d1SDavid du Colombier incref(c); 2853e12c5d1SDavid du Colombier i->c = c; 2863e12c5d1SDavid du Colombier i->type = c->type; 2873e12c5d1SDavid du Colombier i->qid = c->qid; 2883e12c5d1SDavid du Colombier i->mqid = c->mqid; 2893e12c5d1SDavid du Colombier i->mchan = c->mchan; 2903e12c5d1SDavid du Colombier l = &ihash(c->qid.path); 2913e12c5d1SDavid du Colombier i->hash = *l; 2923e12c5d1SDavid du Colombier *l = i; 2933e12c5d1SDavid du Colombier found: 2943e12c5d1SDavid du Colombier unlock(&imagealloc); 2953e12c5d1SDavid du Colombier 2963e12c5d1SDavid du Colombier if(i->s == 0) { 297219b2ee8SDavid du Colombier /* Disaster after commit in exec */ 298219b2ee8SDavid du Colombier if(waserror()) { 299219b2ee8SDavid du Colombier unlock(i); 300219b2ee8SDavid du Colombier pexit(Enovmem, 1); 301219b2ee8SDavid du Colombier } 3023e12c5d1SDavid du Colombier i->s = newseg(type, base, len); 3033e12c5d1SDavid du Colombier i->s->image = i; 3042839d78eSDavid du Colombier i->ref++; 305219b2ee8SDavid du Colombier poperror(); 3063e12c5d1SDavid du Colombier } 3073e12c5d1SDavid du Colombier else 3083e12c5d1SDavid du Colombier incref(i->s); 3093e12c5d1SDavid du Colombier 3103e12c5d1SDavid du Colombier return i; 3113e12c5d1SDavid du Colombier } 3123e12c5d1SDavid du Colombier 3137dd7cddfSDavid du Colombier static struct { 3147dd7cddfSDavid du Colombier int calls; /* times imagereclaim was called */ 3157dd7cddfSDavid du Colombier int loops; /* times the main loop was run */ 3167dd7cddfSDavid du Colombier uvlong ticks; /* total time in the main loop */ 3177dd7cddfSDavid du Colombier uvlong maxt; /* longest time in main loop */ 3187dd7cddfSDavid du Colombier } irstats; 3197dd7cddfSDavid du Colombier 3207dd7cddfSDavid du Colombier static void 3213e12c5d1SDavid du Colombier imagereclaim(void) 3223e12c5d1SDavid du Colombier { 3233e12c5d1SDavid du Colombier Page *p; 3247dd7cddfSDavid du Colombier uvlong ticks; 3253e12c5d1SDavid du Colombier 3267dd7cddfSDavid du Colombier irstats.calls++; 3273e12c5d1SDavid du Colombier /* Somebody is already cleaning the page cache */ 3283e12c5d1SDavid du Colombier if(!canqlock(&imagealloc.ireclaim)) 3293e12c5d1SDavid du Colombier return; 3303e12c5d1SDavid du Colombier 3313e12c5d1SDavid du Colombier lock(&palloc); 3327dd7cddfSDavid du Colombier ticks = fastticks(nil); 3333e12c5d1SDavid du Colombier for(p = palloc.head; p; p = p->next) { 3347dd7cddfSDavid du Colombier if(p->ref == 0 && p->image && canlock(p)) { 3353e12c5d1SDavid du Colombier if(p->ref == 0) 3363e12c5d1SDavid du Colombier uncachepage(p); 3373e12c5d1SDavid du Colombier unlock(p); 3383e12c5d1SDavid du Colombier } 3393e12c5d1SDavid du Colombier } 3407dd7cddfSDavid du Colombier ticks = fastticks(nil) - ticks; 3413e12c5d1SDavid du Colombier unlock(&palloc); 3427dd7cddfSDavid du Colombier irstats.loops++; 3437dd7cddfSDavid du Colombier irstats.ticks += ticks; 3447dd7cddfSDavid du Colombier if(ticks > irstats.maxt) 3457dd7cddfSDavid du Colombier irstats.maxt = ticks; 3467dd7cddfSDavid du Colombier //print("T%llud+", ticks); 3473e12c5d1SDavid du Colombier qunlock(&imagealloc.ireclaim); 3483e12c5d1SDavid du Colombier } 3493e12c5d1SDavid du Colombier 3507dd7cddfSDavid du Colombier /* 3517dd7cddfSDavid du Colombier * since close can block, this has to be called outside of 3527dd7cddfSDavid du Colombier * spin locks. 3537dd7cddfSDavid du Colombier */ 3547dd7cddfSDavid du Colombier static void 3557dd7cddfSDavid du Colombier imagechanreclaim(void) 3567dd7cddfSDavid du Colombier { 3577dd7cddfSDavid du Colombier Chan *c; 3587dd7cddfSDavid du Colombier 3597dd7cddfSDavid du Colombier /* Somebody is already cleaning the image chans */ 3607dd7cddfSDavid du Colombier if(!canqlock(&imagealloc.fcreclaim)) 3617dd7cddfSDavid du Colombier return; 3627dd7cddfSDavid du Colombier 3637dd7cddfSDavid du Colombier /* 3647dd7cddfSDavid du Colombier * We don't have to recheck that nfreechan > 0 after we 3657dd7cddfSDavid du Colombier * acquire the lock, because we're the only ones who decrement 3667dd7cddfSDavid du Colombier * it (the other lock contender increments it), and there's only 3677dd7cddfSDavid du Colombier * one of us thanks to the qlock above. 3687dd7cddfSDavid du Colombier */ 3697dd7cddfSDavid du Colombier while(imagealloc.nfreechan > 0){ 3707dd7cddfSDavid du Colombier lock(&imagealloc); 3717dd7cddfSDavid du Colombier imagealloc.nfreechan--; 3727dd7cddfSDavid du Colombier c = imagealloc.freechan[imagealloc.nfreechan]; 3737dd7cddfSDavid du Colombier unlock(&imagealloc); 3747dd7cddfSDavid du Colombier cclose(c); 3757dd7cddfSDavid du Colombier } 3767dd7cddfSDavid du Colombier 3777dd7cddfSDavid du Colombier qunlock(&imagealloc.fcreclaim); 3787dd7cddfSDavid du Colombier } 3797dd7cddfSDavid du Colombier 3803e12c5d1SDavid du Colombier void 3813e12c5d1SDavid du Colombier putimage(Image *i) 3823e12c5d1SDavid du Colombier { 3837dd7cddfSDavid du Colombier Chan *c, **cp; 3843e12c5d1SDavid du Colombier Image *f, **l; 3853e12c5d1SDavid du Colombier 3867dd7cddfSDavid du Colombier if(i->notext) 3873e12c5d1SDavid du Colombier return; 3883e12c5d1SDavid du Colombier 3893e12c5d1SDavid du Colombier lock(i); 3903e12c5d1SDavid du Colombier if(--i->ref == 0) { 3913e12c5d1SDavid du Colombier l = &ihash(i->qid.path); 3929a747e4fSDavid du Colombier mkqid(&i->qid, ~0, ~0, QTFILE); 3933e12c5d1SDavid du Colombier unlock(i); 3943e12c5d1SDavid du Colombier c = i->c; 3953e12c5d1SDavid du Colombier 3963e12c5d1SDavid du Colombier lock(&imagealloc); 3973e12c5d1SDavid du Colombier for(f = *l; f; f = f->hash) { 3983e12c5d1SDavid du Colombier if(f == i) { 3993e12c5d1SDavid du Colombier *l = i->hash; 4003e12c5d1SDavid du Colombier break; 4013e12c5d1SDavid du Colombier } 4023e12c5d1SDavid du Colombier l = &f->hash; 4033e12c5d1SDavid du Colombier } 4043e12c5d1SDavid du Colombier 4053e12c5d1SDavid du Colombier i->next = imagealloc.free; 4063e12c5d1SDavid du Colombier imagealloc.free = i; 4077dd7cddfSDavid du Colombier 4087dd7cddfSDavid du Colombier /* defer freeing channel till we're out of spin lock's */ 4097dd7cddfSDavid du Colombier if(imagealloc.nfreechan == imagealloc.szfreechan){ 4107dd7cddfSDavid du Colombier imagealloc.szfreechan += NFREECHAN; 4117dd7cddfSDavid du Colombier cp = malloc(imagealloc.szfreechan*sizeof(Chan*)); 4127dd7cddfSDavid du Colombier if(cp == nil) 4137dd7cddfSDavid du Colombier panic("putimage"); 4147dd7cddfSDavid du Colombier memmove(cp, imagealloc.freechan, imagealloc.nfreechan*sizeof(Chan*)); 4157dd7cddfSDavid du Colombier free(imagealloc.freechan); 4167dd7cddfSDavid du Colombier imagealloc.freechan = cp; 4177dd7cddfSDavid du Colombier } 4187dd7cddfSDavid du Colombier imagealloc.freechan[imagealloc.nfreechan++] = c; 4193e12c5d1SDavid du Colombier unlock(&imagealloc); 4203e12c5d1SDavid du Colombier 4213e12c5d1SDavid du Colombier return; 4223e12c5d1SDavid du Colombier } 4233e12c5d1SDavid du Colombier unlock(i); 4243e12c5d1SDavid du Colombier } 4253e12c5d1SDavid du Colombier 4263e12c5d1SDavid du Colombier long 4273e12c5d1SDavid du Colombier ibrk(ulong addr, int seg) 4283e12c5d1SDavid du Colombier { 4293e12c5d1SDavid du Colombier Segment *s, *ns; 4303e12c5d1SDavid du Colombier ulong newtop, newsize; 4317dd7cddfSDavid du Colombier int i, mapsize; 4327dd7cddfSDavid du Colombier Pte **map; 4333e12c5d1SDavid du Colombier 4347dd7cddfSDavid du Colombier s = up->seg[seg]; 4353e12c5d1SDavid du Colombier if(s == 0) 4363e12c5d1SDavid du Colombier error(Ebadarg); 4373e12c5d1SDavid du Colombier 4383e12c5d1SDavid du Colombier if(addr == 0) 4393e12c5d1SDavid du Colombier return s->base; 4403e12c5d1SDavid du Colombier 4413e12c5d1SDavid du Colombier qlock(&s->lk); 4423e12c5d1SDavid du Colombier 4433e12c5d1SDavid du Colombier /* We may start with the bss overlapping the data */ 4443e12c5d1SDavid du Colombier if(addr < s->base) { 4457dd7cddfSDavid du Colombier if(seg != BSEG || up->seg[DSEG] == 0 || addr < up->seg[DSEG]->base) { 4463e12c5d1SDavid du Colombier qunlock(&s->lk); 4473e12c5d1SDavid du Colombier error(Enovmem); 4483e12c5d1SDavid du Colombier } 4493e12c5d1SDavid du Colombier addr = s->base; 4503e12c5d1SDavid du Colombier } 4513e12c5d1SDavid du Colombier 4523e12c5d1SDavid du Colombier newtop = PGROUND(addr); 4533e12c5d1SDavid du Colombier newsize = (newtop-s->base)/BY2PG; 4543e12c5d1SDavid du Colombier if(newtop < s->top) { 4553e12c5d1SDavid du Colombier mfreeseg(s, newtop, (s->top-newtop)/BY2PG); 456*4aeffbf5SDavid du Colombier s->top = newtop; 457*4aeffbf5SDavid du Colombier s->size = newsize; 4583e12c5d1SDavid du Colombier qunlock(&s->lk); 459bd389b36SDavid du Colombier flushmmu(); 4603e12c5d1SDavid du Colombier return 0; 4613e12c5d1SDavid du Colombier } 4623e12c5d1SDavid du Colombier 4637dd7cddfSDavid du Colombier if(swapfull()){ 4647dd7cddfSDavid du Colombier qunlock(&s->lk); 4657dd7cddfSDavid du Colombier error(Enoswap); 4667dd7cddfSDavid du Colombier } 4677dd7cddfSDavid du Colombier 4683e12c5d1SDavid du Colombier for(i = 0; i < NSEG; i++) { 4697dd7cddfSDavid du Colombier ns = up->seg[i]; 4703e12c5d1SDavid du Colombier if(ns == 0 || ns == s) 4713e12c5d1SDavid du Colombier continue; 4723e12c5d1SDavid du Colombier if(newtop >= ns->base && newtop < ns->top) { 4733e12c5d1SDavid du Colombier qunlock(&s->lk); 4743e12c5d1SDavid du Colombier error(Esoverlap); 4753e12c5d1SDavid du Colombier } 4763e12c5d1SDavid du Colombier } 4773e12c5d1SDavid du Colombier 4787dd7cddfSDavid du Colombier if(newsize > (SEGMAPSIZE*PTEPERTAB)) { 4793e12c5d1SDavid du Colombier qunlock(&s->lk); 4803e12c5d1SDavid du Colombier error(Enovmem); 4813e12c5d1SDavid du Colombier } 4827dd7cddfSDavid du Colombier mapsize = ROUND(newsize, PTEPERTAB)/PTEPERTAB; 4837dd7cddfSDavid du Colombier if(mapsize > s->mapsize){ 4847dd7cddfSDavid du Colombier map = smalloc(mapsize*sizeof(Pte*)); 4857dd7cddfSDavid du Colombier memmove(map, s->map, s->mapsize*sizeof(Pte*)); 4867dd7cddfSDavid du Colombier if(s->map != s->ssegmap) 4877dd7cddfSDavid du Colombier free(s->map); 4887dd7cddfSDavid du Colombier s->map = map; 4897dd7cddfSDavid du Colombier s->mapsize = mapsize; 4907dd7cddfSDavid du Colombier } 4913e12c5d1SDavid du Colombier 4923e12c5d1SDavid du Colombier s->top = newtop; 4933e12c5d1SDavid du Colombier s->size = newsize; 4943e12c5d1SDavid du Colombier qunlock(&s->lk); 4953e12c5d1SDavid du Colombier return 0; 4963e12c5d1SDavid du Colombier } 4973e12c5d1SDavid du Colombier 4987dd7cddfSDavid du Colombier /* 4997dd7cddfSDavid du Colombier * called with s->lk locked 5007dd7cddfSDavid du Colombier */ 5013e12c5d1SDavid du Colombier void 5023e12c5d1SDavid du Colombier mfreeseg(Segment *s, ulong start, int pages) 5033e12c5d1SDavid du Colombier { 5047dd7cddfSDavid du Colombier int i, j, size; 5053e12c5d1SDavid du Colombier ulong soff; 5063e12c5d1SDavid du Colombier Page *pg; 5077dd7cddfSDavid du Colombier Page *list; 5083e12c5d1SDavid du Colombier 5093e12c5d1SDavid du Colombier soff = start-s->base; 5103e12c5d1SDavid du Colombier j = (soff&(PTEMAPMEM-1))/BY2PG; 5113e12c5d1SDavid du Colombier 5127dd7cddfSDavid du Colombier size = s->mapsize; 5137dd7cddfSDavid du Colombier list = nil; 5147dd7cddfSDavid du Colombier for(i = soff/PTEMAPMEM; i < size; i++) { 5153e12c5d1SDavid du Colombier if(pages <= 0) 516bd389b36SDavid du Colombier break; 517bd389b36SDavid du Colombier if(s->map[i] == 0) { 518bd389b36SDavid du Colombier pages -= PTEPERTAB-j; 519bd389b36SDavid du Colombier j = 0; 520bd389b36SDavid du Colombier continue; 521bd389b36SDavid du Colombier } 5223e12c5d1SDavid du Colombier while(j < PTEPERTAB) { 523bd389b36SDavid du Colombier pg = s->map[i]->pages[j]; 5243ff48bf5SDavid du Colombier /* 5253ff48bf5SDavid du Colombier * We want to zero s->map[i]->page[j] and putpage(pg), 5264de34a7eSDavid du Colombier * but we have to make sure other processors flush the 5273ff48bf5SDavid du Colombier * entry from their TLBs before the page is freed. 5283ff48bf5SDavid du Colombier * We construct a list of the pages to be freed, zero 5293ff48bf5SDavid du Colombier * the entries, then (below) call procflushseg, and call 5303ff48bf5SDavid du Colombier * putpage on the whole list. 5313ff48bf5SDavid du Colombier * 5323ff48bf5SDavid du Colombier * Swapped-out pages don't appear in TLBs, so it's okay 5333ff48bf5SDavid du Colombier * to putswap those pages before procflushseg. 5343ff48bf5SDavid du Colombier */ 535bd389b36SDavid du Colombier if(pg){ 5363ff48bf5SDavid du Colombier if(onswap(pg)) 5373ff48bf5SDavid du Colombier putswap(pg); 5383ff48bf5SDavid du Colombier else{ 5397dd7cddfSDavid du Colombier pg->next = list; 5407dd7cddfSDavid du Colombier list = pg; 5413e12c5d1SDavid du Colombier } 5423ff48bf5SDavid du Colombier s->map[i]->pages[j] = 0; 5433ff48bf5SDavid du Colombier } 5443e12c5d1SDavid du Colombier if(--pages == 0) 5457dd7cddfSDavid du Colombier goto out; 5463e12c5d1SDavid du Colombier j++; 5473e12c5d1SDavid du Colombier } 5483e12c5d1SDavid du Colombier j = 0; 5493e12c5d1SDavid du Colombier } 5507dd7cddfSDavid du Colombier out: 5517dd7cddfSDavid du Colombier /* flush this seg in all other processes */ 5529a747e4fSDavid du Colombier if(s->ref > 1) 5537dd7cddfSDavid du Colombier procflushseg(s); 5543e12c5d1SDavid du Colombier 5557dd7cddfSDavid du Colombier /* free the pages */ 5567dd7cddfSDavid du Colombier for(pg = list; pg != nil; pg = list){ 5577dd7cddfSDavid du Colombier list = list->next; 5587dd7cddfSDavid du Colombier putpage(pg); 5597dd7cddfSDavid du Colombier } 5607dd7cddfSDavid du Colombier } 5617dd7cddfSDavid du Colombier 5627dd7cddfSDavid du Colombier Segment* 5637dd7cddfSDavid du Colombier isoverlap(Proc *p, ulong va, int len) 564219b2ee8SDavid du Colombier { 565219b2ee8SDavid du Colombier int i; 566219b2ee8SDavid du Colombier Segment *ns; 567219b2ee8SDavid du Colombier ulong newtop; 568219b2ee8SDavid du Colombier 569219b2ee8SDavid du Colombier newtop = va+len; 570219b2ee8SDavid du Colombier for(i = 0; i < NSEG; i++) { 5717dd7cddfSDavid du Colombier ns = p->seg[i]; 572219b2ee8SDavid du Colombier if(ns == 0) 573219b2ee8SDavid du Colombier continue; 574219b2ee8SDavid du Colombier if((newtop > ns->base && newtop <= ns->top) || 575219b2ee8SDavid du Colombier (va >= ns->base && va < ns->top)) 5767dd7cddfSDavid du Colombier return ns; 577219b2ee8SDavid du Colombier } 5787dd7cddfSDavid du Colombier return nil; 5797dd7cddfSDavid du Colombier } 5807dd7cddfSDavid du Colombier 5817dd7cddfSDavid du Colombier int 5827dd7cddfSDavid du Colombier addphysseg(Physseg* new) 5837dd7cddfSDavid du Colombier { 5847dd7cddfSDavid du Colombier Physseg *ps; 5857dd7cddfSDavid du Colombier 5867dd7cddfSDavid du Colombier /* 5877dd7cddfSDavid du Colombier * Check not already entered and there is room 5887dd7cddfSDavid du Colombier * for a new entry and the terminating null entry. 5897dd7cddfSDavid du Colombier */ 5907dd7cddfSDavid du Colombier lock(&physseglock); 5917dd7cddfSDavid du Colombier for(ps = physseg; ps->name; ps++){ 5927dd7cddfSDavid du Colombier if(strcmp(ps->name, new->name) == 0){ 5937dd7cddfSDavid du Colombier unlock(&physseglock); 5947dd7cddfSDavid du Colombier return -1; 5957dd7cddfSDavid du Colombier } 5967dd7cddfSDavid du Colombier } 5977dd7cddfSDavid du Colombier if(ps-physseg >= nelem(physseg)-2){ 5987dd7cddfSDavid du Colombier unlock(&physseglock); 5997dd7cddfSDavid du Colombier return -1; 6007dd7cddfSDavid du Colombier } 6017dd7cddfSDavid du Colombier 6027dd7cddfSDavid du Colombier *ps = *new; 6037dd7cddfSDavid du Colombier unlock(&physseglock); 6047dd7cddfSDavid du Colombier 605219b2ee8SDavid du Colombier return 0; 606219b2ee8SDavid du Colombier } 607219b2ee8SDavid du Colombier 6089a747e4fSDavid du Colombier int 6099a747e4fSDavid du Colombier isphysseg(char *name) 6109a747e4fSDavid du Colombier { 6119a747e4fSDavid du Colombier Physseg *ps; 6129a747e4fSDavid du Colombier int rv = 0; 6139a747e4fSDavid du Colombier 6149a747e4fSDavid du Colombier lock(&physseglock); 6159a747e4fSDavid du Colombier for(ps = physseg; ps->name; ps++){ 6169a747e4fSDavid du Colombier if(strcmp(ps->name, name) == 0){ 6179a747e4fSDavid du Colombier rv = 1; 6189a747e4fSDavid du Colombier break; 6199a747e4fSDavid du Colombier } 6209a747e4fSDavid du Colombier } 6219a747e4fSDavid du Colombier unlock(&physseglock); 6229a747e4fSDavid du Colombier return rv; 6239a747e4fSDavid du Colombier } 6249a747e4fSDavid du Colombier 6253e12c5d1SDavid du Colombier ulong 6263e12c5d1SDavid du Colombier segattach(Proc *p, ulong attr, char *name, ulong va, ulong len) 6273e12c5d1SDavid du Colombier { 6287dd7cddfSDavid du Colombier int sno; 6297dd7cddfSDavid du Colombier Segment *s, *os; 630219b2ee8SDavid du Colombier Physseg *ps; 6313e12c5d1SDavid du Colombier 6324de34a7eSDavid du Colombier if(va != 0 && va >= USTKTOP) 6333e12c5d1SDavid du Colombier error(Ebadarg); 6343e12c5d1SDavid du Colombier 6353e12c5d1SDavid du Colombier validaddr((ulong)name, 1, 0); 6363e12c5d1SDavid du Colombier vmemchr(name, 0, ~0); 6373e12c5d1SDavid du Colombier 6383e12c5d1SDavid du Colombier for(sno = 0; sno < NSEG; sno++) 6397dd7cddfSDavid du Colombier if(p->seg[sno] == nil && sno != ESEG) 6403e12c5d1SDavid du Colombier break; 6413e12c5d1SDavid du Colombier 6423e12c5d1SDavid du Colombier if(sno == NSEG) 6433e12c5d1SDavid du Colombier error(Enovmem); 6443e12c5d1SDavid du Colombier 6459a747e4fSDavid du Colombier /* 6469a747e4fSDavid du Colombier * first look for a global segment with the 6479a747e4fSDavid du Colombier * same name 6489a747e4fSDavid du Colombier */ 6499a747e4fSDavid du Colombier if(_globalsegattach != nil){ 6509a747e4fSDavid du Colombier s = (*_globalsegattach)(p, name); 6519a747e4fSDavid du Colombier if(s != nil){ 6529a747e4fSDavid du Colombier p->seg[sno] = s; 6539a747e4fSDavid du Colombier return s->base; 6549a747e4fSDavid du Colombier } 6559a747e4fSDavid du Colombier } 6569a747e4fSDavid du Colombier 6573e12c5d1SDavid du Colombier len = PGROUND(len); 6587dd7cddfSDavid du Colombier if(len == 0) 6597dd7cddfSDavid du Colombier error(Ebadarg); 660219b2ee8SDavid du Colombier 6617dd7cddfSDavid du Colombier /* 6627dd7cddfSDavid du Colombier * Find a hole in the address space. 6637dd7cddfSDavid du Colombier * Starting at the lowest possible stack address - len, 6647dd7cddfSDavid du Colombier * check for an overlapping segment, and repeat at the 6657dd7cddfSDavid du Colombier * base of that segment - len until either a hole is found 6667dd7cddfSDavid du Colombier * or the address space is exhausted. 6677dd7cddfSDavid du Colombier */ 668219b2ee8SDavid du Colombier if(va == 0) { 669219b2ee8SDavid du Colombier va = p->seg[SSEG]->base - len; 6707dd7cddfSDavid du Colombier for(;;) { 6717dd7cddfSDavid du Colombier os = isoverlap(p, va, len); 6727dd7cddfSDavid du Colombier if(os == nil) 673219b2ee8SDavid du Colombier break; 6747dd7cddfSDavid du Colombier va = os->base; 6757dd7cddfSDavid du Colombier if(len > va) 6767dd7cddfSDavid du Colombier error(Enovmem); 677219b2ee8SDavid du Colombier va -= len; 6783e12c5d1SDavid du Colombier } 679219b2ee8SDavid du Colombier } 680219b2ee8SDavid du Colombier 681219b2ee8SDavid du Colombier va = va&~(BY2PG-1); 6827dd7cddfSDavid du Colombier if(isoverlap(p, va, len) != nil) 683219b2ee8SDavid du Colombier error(Esoverlap); 6843e12c5d1SDavid du Colombier 6853e12c5d1SDavid du Colombier for(ps = physseg; ps->name; ps++) 6863e12c5d1SDavid du Colombier if(strcmp(name, ps->name) == 0) 6873e12c5d1SDavid du Colombier goto found; 6883e12c5d1SDavid du Colombier 6893e12c5d1SDavid du Colombier error(Ebadarg); 6903e12c5d1SDavid du Colombier found: 6913e12c5d1SDavid du Colombier if(len > ps->size) 6923e12c5d1SDavid du Colombier error(Enovmem); 6933e12c5d1SDavid du Colombier 6947dd7cddfSDavid du Colombier attr &= ~SG_TYPE; /* Turn off what is not allowed */ 6953e12c5d1SDavid du Colombier attr |= ps->attr; /* Copy in defaults */ 6963e12c5d1SDavid du Colombier 6973e12c5d1SDavid du Colombier s = newseg(attr, va, len/BY2PG); 698219b2ee8SDavid du Colombier s->pseg = ps; 6997dd7cddfSDavid du Colombier p->seg[sno] = s; 7003e12c5d1SDavid du Colombier 701219b2ee8SDavid du Colombier return va; 7023e12c5d1SDavid du Colombier } 7033e12c5d1SDavid du Colombier 704219b2ee8SDavid du Colombier void 705219b2ee8SDavid du Colombier pteflush(Pte *pte, int s, int e) 706219b2ee8SDavid du Colombier { 707219b2ee8SDavid du Colombier int i; 708219b2ee8SDavid du Colombier Page *p; 709219b2ee8SDavid du Colombier 710219b2ee8SDavid du Colombier for(i = s; i < e; i++) { 711219b2ee8SDavid du Colombier p = pte->pages[i]; 712219b2ee8SDavid du Colombier if(pagedout(p) == 0) 713219b2ee8SDavid du Colombier memset(p->cachectl, PG_TXTFLUSH, sizeof(p->cachectl)); 714219b2ee8SDavid du Colombier } 715219b2ee8SDavid du Colombier } 716219b2ee8SDavid du Colombier 7173e12c5d1SDavid du Colombier long 7183e12c5d1SDavid du Colombier syssegflush(ulong *arg) 7197dd7cddfSDavid du Colombier { 7207dd7cddfSDavid du Colombier Segment *s; 721219b2ee8SDavid du Colombier ulong addr, l; 722219b2ee8SDavid du Colombier Pte *pte; 723219b2ee8SDavid du Colombier int chunk, ps, pe, len; 7243e12c5d1SDavid du Colombier 725219b2ee8SDavid du Colombier addr = arg[0]; 726219b2ee8SDavid du Colombier len = arg[1]; 727219b2ee8SDavid du Colombier 728219b2ee8SDavid du Colombier while(len > 0) { 7297dd7cddfSDavid du Colombier s = seg(up, addr, 1); 7303e12c5d1SDavid du Colombier if(s == 0) 7313e12c5d1SDavid du Colombier error(Ebadarg); 7323e12c5d1SDavid du Colombier 7333e12c5d1SDavid du Colombier s->flushme = 1; 734219b2ee8SDavid du Colombier more: 735219b2ee8SDavid du Colombier l = len; 736219b2ee8SDavid du Colombier if(addr+l > s->top) 737219b2ee8SDavid du Colombier l = s->top - addr; 7383e12c5d1SDavid du Colombier 739219b2ee8SDavid du Colombier ps = addr-s->base; 740219b2ee8SDavid du Colombier pte = s->map[ps/PTEMAPMEM]; 741219b2ee8SDavid du Colombier ps &= PTEMAPMEM-1; 742219b2ee8SDavid du Colombier pe = PTEMAPMEM; 743219b2ee8SDavid du Colombier if(pe-ps > l){ 744219b2ee8SDavid du Colombier pe = ps + l; 745219b2ee8SDavid du Colombier pe = (pe+BY2PG-1)&~(BY2PG-1); 7463e12c5d1SDavid du Colombier } 747219b2ee8SDavid du Colombier if(pe == ps) { 7483e12c5d1SDavid du Colombier qunlock(&s->lk); 749219b2ee8SDavid du Colombier error(Ebadarg); 750219b2ee8SDavid du Colombier } 751219b2ee8SDavid du Colombier 752219b2ee8SDavid du Colombier if(pte) 753219b2ee8SDavid du Colombier pteflush(pte, ps/BY2PG, pe/BY2PG); 754219b2ee8SDavid du Colombier 755219b2ee8SDavid du Colombier chunk = pe-ps; 756219b2ee8SDavid du Colombier len -= chunk; 757219b2ee8SDavid du Colombier addr += chunk; 758219b2ee8SDavid du Colombier 759219b2ee8SDavid du Colombier if(len > 0 && addr < s->top) 760219b2ee8SDavid du Colombier goto more; 761219b2ee8SDavid du Colombier 762219b2ee8SDavid du Colombier qunlock(&s->lk); 763219b2ee8SDavid du Colombier } 7643e12c5d1SDavid du Colombier flushmmu(); 7653e12c5d1SDavid du Colombier return 0; 7663e12c5d1SDavid du Colombier } 7677dd7cddfSDavid du Colombier 7687dd7cddfSDavid du Colombier void 7697dd7cddfSDavid du Colombier segclock(ulong pc) 7707dd7cddfSDavid du Colombier { 7717dd7cddfSDavid du Colombier Segment *s; 7727dd7cddfSDavid du Colombier 7737dd7cddfSDavid du Colombier s = up->seg[TSEG]; 7747dd7cddfSDavid du Colombier if(s == 0 || s->profile == 0) 7757dd7cddfSDavid du Colombier return; 7767dd7cddfSDavid du Colombier 7777dd7cddfSDavid du Colombier s->profile[0] += TK2MS(1); 7787dd7cddfSDavid du Colombier if(pc >= s->base && pc < s->top) { 7797dd7cddfSDavid du Colombier pc -= s->base; 7807dd7cddfSDavid du Colombier s->profile[pc>>LRESPROF] += TK2MS(1); 7817dd7cddfSDavid du Colombier } 7827dd7cddfSDavid du Colombier } 783