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)); 489c63691cSDavid du Colombier if (imagealloc.free == nil) 499c63691cSDavid du Colombier panic("initseg: no memory"); 503e12c5d1SDavid du Colombier ie = &imagealloc.free[conf.nimage-1]; 513e12c5d1SDavid du Colombier for(i = imagealloc.free; i < ie; i++) 523e12c5d1SDavid du Colombier i->next = i+1; 533e12c5d1SDavid du Colombier i->next = 0; 547dd7cddfSDavid du Colombier imagealloc.freechan = malloc(NFREECHAN * sizeof(Chan*)); 557dd7cddfSDavid du Colombier imagealloc.szfreechan = NFREECHAN; 563e12c5d1SDavid du Colombier } 573e12c5d1SDavid du Colombier 583e12c5d1SDavid du Colombier Segment * 593e12c5d1SDavid du Colombier newseg(int type, ulong base, ulong size) 603e12c5d1SDavid du Colombier { 613e12c5d1SDavid du Colombier Segment *s; 627dd7cddfSDavid du Colombier int mapsize; 633e12c5d1SDavid du Colombier 643e12c5d1SDavid du Colombier if(size > (SEGMAPSIZE*PTEPERTAB)) 653e12c5d1SDavid du Colombier error(Enovmem); 663e12c5d1SDavid du Colombier 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; 733c2ddefeSDavid du Colombier s->sema.prev = &s->sema; 743c2ddefeSDavid du Colombier s->sema.next = &s->sema; 757dd7cddfSDavid du Colombier 767dd7cddfSDavid du Colombier mapsize = ROUND(size, PTEPERTAB)/PTEPERTAB; 777dd7cddfSDavid du Colombier if(mapsize > nelem(s->ssegmap)){ 787dd7cddfSDavid du Colombier mapsize *= 2; 79*db551137SDavid du Colombier if(mapsize > SEGMAPSIZE) 80*db551137SDavid du Colombier mapsize = SEGMAPSIZE; 817dd7cddfSDavid du Colombier s->map = smalloc(mapsize*sizeof(Pte*)); 827dd7cddfSDavid du Colombier s->mapsize = mapsize; 837dd7cddfSDavid du Colombier } 847dd7cddfSDavid du Colombier else{ 857dd7cddfSDavid du Colombier s->map = s->ssegmap; 867dd7cddfSDavid du Colombier s->mapsize = nelem(s->ssegmap); 877dd7cddfSDavid du Colombier } 887dd7cddfSDavid du Colombier 893e12c5d1SDavid du Colombier return s; 903e12c5d1SDavid du Colombier } 913e12c5d1SDavid du Colombier 923e12c5d1SDavid du Colombier void 933e12c5d1SDavid du Colombier putseg(Segment *s) 943e12c5d1SDavid du Colombier { 953e12c5d1SDavid du Colombier Pte **pp, **emap; 963e12c5d1SDavid du Colombier Image *i; 973e12c5d1SDavid du Colombier 983e12c5d1SDavid du Colombier if(s == 0) 993e12c5d1SDavid du Colombier return; 1003e12c5d1SDavid du Colombier 1013e12c5d1SDavid du Colombier i = s->image; 102219b2ee8SDavid du Colombier if(i != 0) { 1033e12c5d1SDavid du Colombier lock(i); 104219b2ee8SDavid du Colombier lock(s); 105219b2ee8SDavid du Colombier if(i->s == s && s->ref == 1) 1063e12c5d1SDavid du Colombier i->s = 0; 1073e12c5d1SDavid du Colombier unlock(i); 1083e12c5d1SDavid du Colombier } 109219b2ee8SDavid du Colombier else 110219b2ee8SDavid du Colombier lock(s); 1113e12c5d1SDavid du Colombier 112219b2ee8SDavid du Colombier s->ref--; 113219b2ee8SDavid du Colombier if(s->ref != 0) { 114219b2ee8SDavid du Colombier unlock(s); 115219b2ee8SDavid du Colombier return; 116219b2ee8SDavid du Colombier } 1179a747e4fSDavid du Colombier unlock(s); 118219b2ee8SDavid du Colombier 1193e12c5d1SDavid du Colombier qlock(&s->lk); 1203e12c5d1SDavid du Colombier if(i) 1213e12c5d1SDavid du Colombier putimage(i); 1223e12c5d1SDavid du Colombier 1237dd7cddfSDavid du Colombier emap = &s->map[s->mapsize]; 1243e12c5d1SDavid du Colombier for(pp = s->map; pp < emap; pp++) 1253e12c5d1SDavid du Colombier if(*pp) 1263e12c5d1SDavid du Colombier freepte(s, *pp); 1273e12c5d1SDavid du Colombier 1283e12c5d1SDavid du Colombier qunlock(&s->lk); 1297dd7cddfSDavid du Colombier if(s->map != s->ssegmap) 1307dd7cddfSDavid du Colombier free(s->map); 1317dd7cddfSDavid du Colombier if(s->profile != 0) 1327dd7cddfSDavid du Colombier free(s->profile); 1333e12c5d1SDavid du Colombier free(s); 1343e12c5d1SDavid du Colombier } 1353e12c5d1SDavid du Colombier 1363e12c5d1SDavid du Colombier void 1373e12c5d1SDavid du Colombier relocateseg(Segment *s, ulong offset) 1383e12c5d1SDavid du Colombier { 1397dd7cddfSDavid du Colombier Page **pg, *x; 1407dd7cddfSDavid du Colombier Pte *pte, **p, **endpte; 1413e12c5d1SDavid du Colombier 1427dd7cddfSDavid du Colombier endpte = &s->map[s->mapsize]; 1433e12c5d1SDavid du Colombier for(p = s->map; p < endpte; p++) { 1447dd7cddfSDavid du Colombier if(*p == 0) 1457dd7cddfSDavid du Colombier continue; 1467dd7cddfSDavid du Colombier pte = *p; 1477dd7cddfSDavid du Colombier for(pg = pte->first; pg <= pte->last; pg++) { 1487dd7cddfSDavid du Colombier if(x = *pg) 1497dd7cddfSDavid du Colombier x->va += offset; 1503e12c5d1SDavid du Colombier } 1513e12c5d1SDavid du Colombier } 1523e12c5d1SDavid du Colombier } 1533e12c5d1SDavid du Colombier 1543e12c5d1SDavid du Colombier Segment* 155bd389b36SDavid du Colombier dupseg(Segment **seg, int segno, int share) 1563e12c5d1SDavid du Colombier { 1577dd7cddfSDavid du Colombier int i, size; 1583e12c5d1SDavid du Colombier Pte *pte; 159bd389b36SDavid du Colombier Segment *n, *s; 1603e12c5d1SDavid du Colombier 1613e12c5d1SDavid du Colombier SET(n); 162bd389b36SDavid du Colombier s = seg[segno]; 163bd389b36SDavid du Colombier 16480ee5cbfSDavid du Colombier qlock(&s->lk); 16580ee5cbfSDavid du Colombier if(waserror()){ 16680ee5cbfSDavid du Colombier qunlock(&s->lk); 16780ee5cbfSDavid du Colombier nexterror(); 16880ee5cbfSDavid du Colombier } 1693e12c5d1SDavid du Colombier switch(s->type&SG_TYPE) { 1703e12c5d1SDavid du Colombier case SG_TEXT: /* New segment shares pte set */ 1713e12c5d1SDavid du Colombier case SG_SHARED: 1723e12c5d1SDavid du Colombier case SG_PHYSICAL: 17380ee5cbfSDavid du Colombier goto sameseg; 1743e12c5d1SDavid du Colombier 1753e12c5d1SDavid du Colombier case SG_STACK: 1763e12c5d1SDavid du Colombier n = newseg(s->type, s->base, s->size); 1773e12c5d1SDavid du Colombier break; 1783e12c5d1SDavid du Colombier 1793e12c5d1SDavid du Colombier case SG_BSS: /* Just copy on write */ 1809a747e4fSDavid du Colombier if(share) 18180ee5cbfSDavid du Colombier goto sameseg; 1823e12c5d1SDavid du Colombier n = newseg(s->type, s->base, s->size); 1833e12c5d1SDavid du Colombier break; 1843e12c5d1SDavid du Colombier 1853e12c5d1SDavid du Colombier case SG_DATA: /* Copy on write plus demand load info */ 18680ee5cbfSDavid du Colombier if(segno == TSEG){ 18780ee5cbfSDavid du Colombier poperror(); 18880ee5cbfSDavid du Colombier qunlock(&s->lk); 189bd389b36SDavid du Colombier return data2txt(s); 1903e12c5d1SDavid du Colombier } 19180ee5cbfSDavid du Colombier 1929a747e4fSDavid du Colombier if(share) 19380ee5cbfSDavid du Colombier goto sameseg; 1943e12c5d1SDavid du Colombier n = newseg(s->type, s->base, s->size); 1953e12c5d1SDavid du Colombier 1963e12c5d1SDavid du Colombier incref(s->image); 1973e12c5d1SDavid du Colombier n->image = s->image; 1983e12c5d1SDavid du Colombier n->fstart = s->fstart; 1993e12c5d1SDavid du Colombier n->flen = s->flen; 2003e12c5d1SDavid du Colombier break; 2013e12c5d1SDavid du Colombier } 2027dd7cddfSDavid du Colombier size = s->mapsize; 2037dd7cddfSDavid du Colombier for(i = 0; i < size; i++) 2043e12c5d1SDavid du Colombier if(pte = s->map[i]) 2053e12c5d1SDavid du Colombier n->map[i] = ptecpy(pte); 2063e12c5d1SDavid du Colombier 2073e12c5d1SDavid du Colombier n->flushme = s->flushme; 2089a747e4fSDavid du Colombier if(s->ref > 1) 2099a747e4fSDavid du Colombier procflushseg(s); 21080ee5cbfSDavid du Colombier poperror(); 2113e12c5d1SDavid du Colombier qunlock(&s->lk); 2123e12c5d1SDavid du Colombier return n; 21380ee5cbfSDavid du Colombier 21480ee5cbfSDavid du Colombier sameseg: 21580ee5cbfSDavid du Colombier incref(s); 21680ee5cbfSDavid du Colombier poperror(); 21780ee5cbfSDavid du Colombier qunlock(&s->lk); 21880ee5cbfSDavid du Colombier return s; 2193e12c5d1SDavid du Colombier } 2203e12c5d1SDavid du Colombier 2213e12c5d1SDavid du Colombier void 2223e12c5d1SDavid du Colombier segpage(Segment *s, Page *p) 2233e12c5d1SDavid du Colombier { 2243e12c5d1SDavid du Colombier Pte **pte; 2253e12c5d1SDavid du Colombier ulong off; 2263e12c5d1SDavid du Colombier Page **pg; 2273e12c5d1SDavid du Colombier 2283e12c5d1SDavid du Colombier if(p->va < s->base || p->va >= s->top) 2293e12c5d1SDavid du Colombier panic("segpage"); 2303e12c5d1SDavid du Colombier 2313e12c5d1SDavid du Colombier off = p->va - s->base; 2323e12c5d1SDavid du Colombier pte = &s->map[off/PTEMAPMEM]; 2333e12c5d1SDavid du Colombier if(*pte == 0) 2343e12c5d1SDavid du Colombier *pte = ptealloc(); 2353e12c5d1SDavid du Colombier 2363e12c5d1SDavid du Colombier pg = &(*pte)->pages[(off&(PTEMAPMEM-1))/BY2PG]; 2373e12c5d1SDavid du Colombier *pg = p; 2383e12c5d1SDavid du Colombier if(pg < (*pte)->first) 2393e12c5d1SDavid du Colombier (*pte)->first = pg; 2403e12c5d1SDavid du Colombier if(pg > (*pte)->last) 2413e12c5d1SDavid du Colombier (*pte)->last = pg; 2423e12c5d1SDavid du Colombier } 2433e12c5d1SDavid du Colombier 2443e12c5d1SDavid du Colombier Image* 2453e12c5d1SDavid du Colombier attachimage(int type, Chan *c, ulong base, ulong len) 2463e12c5d1SDavid du Colombier { 2473e12c5d1SDavid du Colombier Image *i, **l; 2483e12c5d1SDavid du Colombier 2497dd7cddfSDavid du Colombier /* reclaim any free channels from reclaimed segments */ 2507dd7cddfSDavid du Colombier if(imagealloc.nfreechan) 2517dd7cddfSDavid du Colombier imagechanreclaim(); 2527dd7cddfSDavid du Colombier 2533e12c5d1SDavid du Colombier lock(&imagealloc); 2543e12c5d1SDavid du Colombier 2553e12c5d1SDavid du Colombier /* 2563e12c5d1SDavid du Colombier * Search the image cache for remains of the text from a previous 2573e12c5d1SDavid du Colombier * or currently running incarnation 2583e12c5d1SDavid du Colombier */ 2593e12c5d1SDavid du Colombier for(i = ihash(c->qid.path); i; i = i->hash) { 2603e12c5d1SDavid du Colombier if(c->qid.path == i->qid.path) { 2613e12c5d1SDavid du Colombier lock(i); 2623e12c5d1SDavid du Colombier if(eqqid(c->qid, i->qid) && 2633e12c5d1SDavid du Colombier eqqid(c->mqid, i->mqid) && 2643e12c5d1SDavid du Colombier c->mchan == i->mchan && 2653e12c5d1SDavid du Colombier c->type == i->type) { 2663e12c5d1SDavid du Colombier goto found; 2673e12c5d1SDavid du Colombier } 2683e12c5d1SDavid du Colombier unlock(i); 2693e12c5d1SDavid du Colombier } 2703e12c5d1SDavid du Colombier } 2713e12c5d1SDavid du Colombier 2723e12c5d1SDavid du Colombier /* 2733e12c5d1SDavid du Colombier * imagereclaim dumps pages from the free list which are cached by image 2743e12c5d1SDavid du Colombier * structures. This should free some image structures. 2753e12c5d1SDavid du Colombier */ 2763e12c5d1SDavid du Colombier while(!(i = imagealloc.free)) { 2773e12c5d1SDavid du Colombier unlock(&imagealloc); 2783e12c5d1SDavid du Colombier imagereclaim(); 2797dd7cddfSDavid du Colombier sched(); 2803e12c5d1SDavid du Colombier lock(&imagealloc); 2813e12c5d1SDavid du Colombier } 2823e12c5d1SDavid du Colombier 2833e12c5d1SDavid du Colombier imagealloc.free = i->next; 2843e12c5d1SDavid du Colombier 2853e12c5d1SDavid du Colombier lock(i); 2863e12c5d1SDavid du Colombier incref(c); 2873e12c5d1SDavid du Colombier i->c = c; 2883e12c5d1SDavid du Colombier i->type = c->type; 2893e12c5d1SDavid du Colombier i->qid = c->qid; 2903e12c5d1SDavid du Colombier i->mqid = c->mqid; 2913e12c5d1SDavid du Colombier i->mchan = c->mchan; 2923e12c5d1SDavid du Colombier l = &ihash(c->qid.path); 2933e12c5d1SDavid du Colombier i->hash = *l; 2943e12c5d1SDavid du Colombier *l = i; 2953e12c5d1SDavid du Colombier found: 2963e12c5d1SDavid du Colombier unlock(&imagealloc); 2973e12c5d1SDavid du Colombier 2983e12c5d1SDavid du Colombier if(i->s == 0) { 299219b2ee8SDavid du Colombier /* Disaster after commit in exec */ 300219b2ee8SDavid du Colombier if(waserror()) { 301219b2ee8SDavid du Colombier unlock(i); 302219b2ee8SDavid du Colombier pexit(Enovmem, 1); 303219b2ee8SDavid du Colombier } 3043e12c5d1SDavid du Colombier i->s = newseg(type, base, len); 3053e12c5d1SDavid du Colombier i->s->image = i; 3062839d78eSDavid du Colombier i->ref++; 307219b2ee8SDavid du Colombier poperror(); 3083e12c5d1SDavid du Colombier } 3093e12c5d1SDavid du Colombier else 3103e12c5d1SDavid du Colombier incref(i->s); 3113e12c5d1SDavid du Colombier 3123e12c5d1SDavid du Colombier return i; 3133e12c5d1SDavid du Colombier } 3143e12c5d1SDavid du Colombier 3157dd7cddfSDavid du Colombier static struct { 3167dd7cddfSDavid du Colombier int calls; /* times imagereclaim was called */ 3177dd7cddfSDavid du Colombier int loops; /* times the main loop was run */ 3187dd7cddfSDavid du Colombier uvlong ticks; /* total time in the main loop */ 3197dd7cddfSDavid du Colombier uvlong maxt; /* longest time in main loop */ 3207dd7cddfSDavid du Colombier } irstats; 3217dd7cddfSDavid du Colombier 3227dd7cddfSDavid du Colombier static void 3233e12c5d1SDavid du Colombier imagereclaim(void) 3243e12c5d1SDavid du Colombier { 3255437ee90SDavid du Colombier int n; 3263e12c5d1SDavid du Colombier Page *p; 3277dd7cddfSDavid du Colombier uvlong ticks; 3283e12c5d1SDavid du Colombier 3297dd7cddfSDavid du Colombier irstats.calls++; 3303e12c5d1SDavid du Colombier /* Somebody is already cleaning the page cache */ 3313e12c5d1SDavid du Colombier if(!canqlock(&imagealloc.ireclaim)) 3323e12c5d1SDavid du Colombier return; 3333e12c5d1SDavid du Colombier 3343e12c5d1SDavid du Colombier lock(&palloc); 3357dd7cddfSDavid du Colombier ticks = fastticks(nil); 3365437ee90SDavid du Colombier n = 0; 3375437ee90SDavid du Colombier /* 3385437ee90SDavid du Colombier * All the pages with images backing them are at the 3395437ee90SDavid du Colombier * end of the list (see putpage) so start there and work 3405437ee90SDavid du Colombier * backward. 3415437ee90SDavid du Colombier */ 3425437ee90SDavid du Colombier for(p = palloc.tail; p && p->image && n<1000; p = p->prev) { 3435437ee90SDavid du Colombier if(p->ref == 0 && canlock(p)) { 3445437ee90SDavid du Colombier if(p->ref == 0) { 3455437ee90SDavid du Colombier n++; 3463e12c5d1SDavid du Colombier uncachepage(p); 3475437ee90SDavid du Colombier } 3483e12c5d1SDavid du Colombier unlock(p); 3493e12c5d1SDavid du Colombier } 3503e12c5d1SDavid du Colombier } 3517dd7cddfSDavid du Colombier ticks = fastticks(nil) - ticks; 3523e12c5d1SDavid du Colombier unlock(&palloc); 3537dd7cddfSDavid du Colombier irstats.loops++; 3547dd7cddfSDavid du Colombier irstats.ticks += ticks; 3557dd7cddfSDavid du Colombier if(ticks > irstats.maxt) 3567dd7cddfSDavid du Colombier irstats.maxt = ticks; 3577dd7cddfSDavid du Colombier //print("T%llud+", ticks); 3583e12c5d1SDavid du Colombier qunlock(&imagealloc.ireclaim); 3593e12c5d1SDavid du Colombier } 3603e12c5d1SDavid du Colombier 3617dd7cddfSDavid du Colombier /* 3627dd7cddfSDavid du Colombier * since close can block, this has to be called outside of 3637dd7cddfSDavid du Colombier * spin locks. 3647dd7cddfSDavid du Colombier */ 3657dd7cddfSDavid du Colombier static void 3667dd7cddfSDavid du Colombier imagechanreclaim(void) 3677dd7cddfSDavid du Colombier { 3687dd7cddfSDavid du Colombier Chan *c; 3697dd7cddfSDavid du Colombier 3707dd7cddfSDavid du Colombier /* Somebody is already cleaning the image chans */ 3717dd7cddfSDavid du Colombier if(!canqlock(&imagealloc.fcreclaim)) 3727dd7cddfSDavid du Colombier return; 3737dd7cddfSDavid du Colombier 3747dd7cddfSDavid du Colombier /* 3757dd7cddfSDavid du Colombier * We don't have to recheck that nfreechan > 0 after we 3767dd7cddfSDavid du Colombier * acquire the lock, because we're the only ones who decrement 3777dd7cddfSDavid du Colombier * it (the other lock contender increments it), and there's only 3787dd7cddfSDavid du Colombier * one of us thanks to the qlock above. 3797dd7cddfSDavid du Colombier */ 3807dd7cddfSDavid du Colombier while(imagealloc.nfreechan > 0){ 3817dd7cddfSDavid du Colombier lock(&imagealloc); 3827dd7cddfSDavid du Colombier imagealloc.nfreechan--; 3837dd7cddfSDavid du Colombier c = imagealloc.freechan[imagealloc.nfreechan]; 3847dd7cddfSDavid du Colombier unlock(&imagealloc); 3857dd7cddfSDavid du Colombier cclose(c); 3867dd7cddfSDavid du Colombier } 3877dd7cddfSDavid du Colombier 3887dd7cddfSDavid du Colombier qunlock(&imagealloc.fcreclaim); 3897dd7cddfSDavid du Colombier } 3907dd7cddfSDavid du Colombier 3913e12c5d1SDavid du Colombier void 3923e12c5d1SDavid du Colombier putimage(Image *i) 3933e12c5d1SDavid du Colombier { 3947dd7cddfSDavid du Colombier Chan *c, **cp; 3953e12c5d1SDavid du Colombier Image *f, **l; 3963e12c5d1SDavid du Colombier 3977dd7cddfSDavid du Colombier if(i->notext) 3983e12c5d1SDavid du Colombier return; 3993e12c5d1SDavid du Colombier 4003e12c5d1SDavid du Colombier lock(i); 4013e12c5d1SDavid du Colombier if(--i->ref == 0) { 4023e12c5d1SDavid du Colombier l = &ihash(i->qid.path); 4039a747e4fSDavid du Colombier mkqid(&i->qid, ~0, ~0, QTFILE); 4043e12c5d1SDavid du Colombier unlock(i); 4053e12c5d1SDavid du Colombier c = i->c; 4063e12c5d1SDavid du Colombier 4073e12c5d1SDavid du Colombier lock(&imagealloc); 4083e12c5d1SDavid du Colombier for(f = *l; f; f = f->hash) { 4093e12c5d1SDavid du Colombier if(f == i) { 4103e12c5d1SDavid du Colombier *l = i->hash; 4113e12c5d1SDavid du Colombier break; 4123e12c5d1SDavid du Colombier } 4133e12c5d1SDavid du Colombier l = &f->hash; 4143e12c5d1SDavid du Colombier } 4153e12c5d1SDavid du Colombier 4163e12c5d1SDavid du Colombier i->next = imagealloc.free; 4173e12c5d1SDavid du Colombier imagealloc.free = i; 4187dd7cddfSDavid du Colombier 4197dd7cddfSDavid du Colombier /* defer freeing channel till we're out of spin lock's */ 4207dd7cddfSDavid du Colombier if(imagealloc.nfreechan == imagealloc.szfreechan){ 4217dd7cddfSDavid du Colombier imagealloc.szfreechan += NFREECHAN; 4227dd7cddfSDavid du Colombier cp = malloc(imagealloc.szfreechan*sizeof(Chan*)); 4237dd7cddfSDavid du Colombier if(cp == nil) 4247dd7cddfSDavid du Colombier panic("putimage"); 4257dd7cddfSDavid du Colombier memmove(cp, imagealloc.freechan, imagealloc.nfreechan*sizeof(Chan*)); 4267dd7cddfSDavid du Colombier free(imagealloc.freechan); 4277dd7cddfSDavid du Colombier imagealloc.freechan = cp; 4287dd7cddfSDavid du Colombier } 4297dd7cddfSDavid du Colombier imagealloc.freechan[imagealloc.nfreechan++] = c; 4303e12c5d1SDavid du Colombier unlock(&imagealloc); 4313e12c5d1SDavid du Colombier 4323e12c5d1SDavid du Colombier return; 4333e12c5d1SDavid du Colombier } 4343e12c5d1SDavid du Colombier unlock(i); 4353e12c5d1SDavid du Colombier } 4363e12c5d1SDavid du Colombier 4373e12c5d1SDavid du Colombier long 4383e12c5d1SDavid du Colombier ibrk(ulong addr, int seg) 4393e12c5d1SDavid du Colombier { 4403e12c5d1SDavid du Colombier Segment *s, *ns; 4413e12c5d1SDavid du Colombier ulong newtop, newsize; 4427dd7cddfSDavid du Colombier int i, mapsize; 4437dd7cddfSDavid du Colombier Pte **map; 4443e12c5d1SDavid du Colombier 4457dd7cddfSDavid du Colombier s = up->seg[seg]; 4463e12c5d1SDavid du Colombier if(s == 0) 4473e12c5d1SDavid du Colombier error(Ebadarg); 4483e12c5d1SDavid du Colombier 4493e12c5d1SDavid du Colombier if(addr == 0) 4503e12c5d1SDavid du Colombier return s->base; 4513e12c5d1SDavid du Colombier 4523e12c5d1SDavid du Colombier qlock(&s->lk); 4533e12c5d1SDavid du Colombier 4543e12c5d1SDavid du Colombier /* We may start with the bss overlapping the data */ 4553e12c5d1SDavid du Colombier if(addr < s->base) { 4567dd7cddfSDavid du Colombier if(seg != BSEG || up->seg[DSEG] == 0 || addr < up->seg[DSEG]->base) { 4573e12c5d1SDavid du Colombier qunlock(&s->lk); 4583e12c5d1SDavid du Colombier error(Enovmem); 4593e12c5d1SDavid du Colombier } 4603e12c5d1SDavid du Colombier addr = s->base; 4613e12c5d1SDavid du Colombier } 4623e12c5d1SDavid du Colombier 4633e12c5d1SDavid du Colombier newtop = PGROUND(addr); 4643e12c5d1SDavid du Colombier newsize = (newtop-s->base)/BY2PG; 4653e12c5d1SDavid du Colombier if(newtop < s->top) { 466d1be6b08SDavid du Colombier /* 467d1be6b08SDavid du Colombier * do not shrink a segment shared with other procs, as the 468d1be6b08SDavid du Colombier * to-be-freed address space may have been passed to the kernel 469d1be6b08SDavid du Colombier * already by another proc and is past the validaddr stage. 470d1be6b08SDavid du Colombier */ 471d1be6b08SDavid du Colombier if(s->ref > 1){ 472d1be6b08SDavid du Colombier qunlock(&s->lk); 473d1be6b08SDavid du Colombier error(Einuse); 474d1be6b08SDavid du Colombier } 4753e12c5d1SDavid du Colombier mfreeseg(s, newtop, (s->top-newtop)/BY2PG); 4764aeffbf5SDavid du Colombier s->top = newtop; 4774aeffbf5SDavid du Colombier s->size = newsize; 4783e12c5d1SDavid du Colombier qunlock(&s->lk); 479bd389b36SDavid du Colombier flushmmu(); 4803e12c5d1SDavid du Colombier return 0; 4813e12c5d1SDavid du Colombier } 4823e12c5d1SDavid du Colombier 4833e12c5d1SDavid du Colombier for(i = 0; i < NSEG; i++) { 4847dd7cddfSDavid du Colombier ns = up->seg[i]; 4853e12c5d1SDavid du Colombier if(ns == 0 || ns == s) 4863e12c5d1SDavid du Colombier continue; 4873e12c5d1SDavid du Colombier if(newtop >= ns->base && newtop < ns->top) { 4883e12c5d1SDavid du Colombier qunlock(&s->lk); 4893e12c5d1SDavid du Colombier error(Esoverlap); 4903e12c5d1SDavid du Colombier } 4913e12c5d1SDavid du Colombier } 4923e12c5d1SDavid du Colombier 4937dd7cddfSDavid du Colombier if(newsize > (SEGMAPSIZE*PTEPERTAB)) { 4943e12c5d1SDavid du Colombier qunlock(&s->lk); 4953e12c5d1SDavid du Colombier error(Enovmem); 4963e12c5d1SDavid du Colombier } 4977dd7cddfSDavid du Colombier mapsize = ROUND(newsize, PTEPERTAB)/PTEPERTAB; 4987dd7cddfSDavid du Colombier if(mapsize > s->mapsize){ 4997dd7cddfSDavid du Colombier map = smalloc(mapsize*sizeof(Pte*)); 5007dd7cddfSDavid du Colombier memmove(map, s->map, s->mapsize*sizeof(Pte*)); 5017dd7cddfSDavid du Colombier if(s->map != s->ssegmap) 5027dd7cddfSDavid du Colombier free(s->map); 5037dd7cddfSDavid du Colombier s->map = map; 5047dd7cddfSDavid du Colombier s->mapsize = mapsize; 5057dd7cddfSDavid du Colombier } 5063e12c5d1SDavid du Colombier 5073e12c5d1SDavid du Colombier s->top = newtop; 5083e12c5d1SDavid du Colombier s->size = newsize; 5093e12c5d1SDavid du Colombier qunlock(&s->lk); 5103e12c5d1SDavid du Colombier return 0; 5113e12c5d1SDavid du Colombier } 5123e12c5d1SDavid du Colombier 5137dd7cddfSDavid du Colombier /* 5147dd7cddfSDavid du Colombier * called with s->lk locked 5157dd7cddfSDavid du Colombier */ 5163e12c5d1SDavid du Colombier void 5173e12c5d1SDavid du Colombier mfreeseg(Segment *s, ulong start, int pages) 5183e12c5d1SDavid du Colombier { 5197dd7cddfSDavid du Colombier int i, j, size; 5203e12c5d1SDavid du Colombier ulong soff; 5213e12c5d1SDavid du Colombier Page *pg; 5227dd7cddfSDavid du Colombier Page *list; 5233e12c5d1SDavid du Colombier 5243e12c5d1SDavid du Colombier soff = start-s->base; 5253e12c5d1SDavid du Colombier j = (soff&(PTEMAPMEM-1))/BY2PG; 5263e12c5d1SDavid du Colombier 5277dd7cddfSDavid du Colombier size = s->mapsize; 5287dd7cddfSDavid du Colombier list = nil; 5297dd7cddfSDavid du Colombier for(i = soff/PTEMAPMEM; i < size; i++) { 5303e12c5d1SDavid du Colombier if(pages <= 0) 531bd389b36SDavid du Colombier break; 532bd389b36SDavid du Colombier if(s->map[i] == 0) { 533bd389b36SDavid du Colombier pages -= PTEPERTAB-j; 534bd389b36SDavid du Colombier j = 0; 535bd389b36SDavid du Colombier continue; 536bd389b36SDavid du Colombier } 5373e12c5d1SDavid du Colombier while(j < PTEPERTAB) { 538bd389b36SDavid du Colombier pg = s->map[i]->pages[j]; 5393ff48bf5SDavid du Colombier /* 5403ff48bf5SDavid du Colombier * We want to zero s->map[i]->page[j] and putpage(pg), 5414de34a7eSDavid du Colombier * but we have to make sure other processors flush the 5423ff48bf5SDavid du Colombier * entry from their TLBs before the page is freed. 5433ff48bf5SDavid du Colombier * We construct a list of the pages to be freed, zero 5443ff48bf5SDavid du Colombier * the entries, then (below) call procflushseg, and call 5453ff48bf5SDavid du Colombier * putpage on the whole list. 5463ff48bf5SDavid du Colombier * 5473ff48bf5SDavid du Colombier * Swapped-out pages don't appear in TLBs, so it's okay 5483ff48bf5SDavid du Colombier * to putswap those pages before procflushseg. 5493ff48bf5SDavid du Colombier */ 550bd389b36SDavid du Colombier if(pg){ 5513ff48bf5SDavid du Colombier if(onswap(pg)) 5523ff48bf5SDavid du Colombier putswap(pg); 5533ff48bf5SDavid du Colombier else{ 5547dd7cddfSDavid du Colombier pg->next = list; 5557dd7cddfSDavid du Colombier list = pg; 5563e12c5d1SDavid du Colombier } 5573ff48bf5SDavid du Colombier s->map[i]->pages[j] = 0; 5583ff48bf5SDavid du Colombier } 5593e12c5d1SDavid du Colombier if(--pages == 0) 5607dd7cddfSDavid du Colombier goto out; 5613e12c5d1SDavid du Colombier j++; 5623e12c5d1SDavid du Colombier } 5633e12c5d1SDavid du Colombier j = 0; 5643e12c5d1SDavid du Colombier } 5657dd7cddfSDavid du Colombier out: 5667dd7cddfSDavid du Colombier /* flush this seg in all other processes */ 5679a747e4fSDavid du Colombier if(s->ref > 1) 5687dd7cddfSDavid du Colombier procflushseg(s); 5693e12c5d1SDavid du Colombier 5707dd7cddfSDavid du Colombier /* free the pages */ 5717dd7cddfSDavid du Colombier for(pg = list; pg != nil; pg = list){ 5727dd7cddfSDavid du Colombier list = list->next; 5737dd7cddfSDavid du Colombier putpage(pg); 5747dd7cddfSDavid du Colombier } 5757dd7cddfSDavid du Colombier } 5767dd7cddfSDavid du Colombier 5777dd7cddfSDavid du Colombier Segment* 5787dd7cddfSDavid du Colombier isoverlap(Proc *p, ulong va, int len) 579219b2ee8SDavid du Colombier { 580219b2ee8SDavid du Colombier int i; 581219b2ee8SDavid du Colombier Segment *ns; 582219b2ee8SDavid du Colombier ulong newtop; 583219b2ee8SDavid du Colombier 584219b2ee8SDavid du Colombier newtop = va+len; 585219b2ee8SDavid du Colombier for(i = 0; i < NSEG; i++) { 5867dd7cddfSDavid du Colombier ns = p->seg[i]; 587219b2ee8SDavid du Colombier if(ns == 0) 588219b2ee8SDavid du Colombier continue; 589219b2ee8SDavid du Colombier if((newtop > ns->base && newtop <= ns->top) || 590219b2ee8SDavid du Colombier (va >= ns->base && va < ns->top)) 5917dd7cddfSDavid du Colombier return ns; 592219b2ee8SDavid du Colombier } 5937dd7cddfSDavid du Colombier return nil; 5947dd7cddfSDavid du Colombier } 5957dd7cddfSDavid du Colombier 5967dd7cddfSDavid du Colombier int 5977dd7cddfSDavid du Colombier addphysseg(Physseg* new) 5987dd7cddfSDavid du Colombier { 5997dd7cddfSDavid du Colombier Physseg *ps; 6007dd7cddfSDavid du Colombier 6017dd7cddfSDavid du Colombier /* 6027dd7cddfSDavid du Colombier * Check not already entered and there is room 6037dd7cddfSDavid du Colombier * for a new entry and the terminating null entry. 6047dd7cddfSDavid du Colombier */ 6057dd7cddfSDavid du Colombier lock(&physseglock); 6067dd7cddfSDavid du Colombier for(ps = physseg; ps->name; ps++){ 6077dd7cddfSDavid du Colombier if(strcmp(ps->name, new->name) == 0){ 6087dd7cddfSDavid du Colombier unlock(&physseglock); 6097dd7cddfSDavid du Colombier return -1; 6107dd7cddfSDavid du Colombier } 6117dd7cddfSDavid du Colombier } 6127dd7cddfSDavid du Colombier if(ps-physseg >= nelem(physseg)-2){ 6137dd7cddfSDavid du Colombier unlock(&physseglock); 6147dd7cddfSDavid du Colombier return -1; 6157dd7cddfSDavid du Colombier } 6167dd7cddfSDavid du Colombier 6177dd7cddfSDavid du Colombier *ps = *new; 6187dd7cddfSDavid du Colombier unlock(&physseglock); 6197dd7cddfSDavid du Colombier 620219b2ee8SDavid du Colombier return 0; 621219b2ee8SDavid du Colombier } 622219b2ee8SDavid du Colombier 6239a747e4fSDavid du Colombier int 6249a747e4fSDavid du Colombier isphysseg(char *name) 6259a747e4fSDavid du Colombier { 6269a747e4fSDavid du Colombier Physseg *ps; 6279a747e4fSDavid du Colombier int rv = 0; 6289a747e4fSDavid du Colombier 6299a747e4fSDavid du Colombier lock(&physseglock); 6309a747e4fSDavid du Colombier for(ps = physseg; ps->name; ps++){ 6319a747e4fSDavid du Colombier if(strcmp(ps->name, name) == 0){ 6329a747e4fSDavid du Colombier rv = 1; 6339a747e4fSDavid du Colombier break; 6349a747e4fSDavid du Colombier } 6359a747e4fSDavid du Colombier } 6369a747e4fSDavid du Colombier unlock(&physseglock); 6379a747e4fSDavid du Colombier return rv; 6389a747e4fSDavid du Colombier } 6399a747e4fSDavid du Colombier 6403e12c5d1SDavid du Colombier ulong 6413e12c5d1SDavid du Colombier segattach(Proc *p, ulong attr, char *name, ulong va, ulong len) 6423e12c5d1SDavid du Colombier { 6437dd7cddfSDavid du Colombier int sno; 6447dd7cddfSDavid du Colombier Segment *s, *os; 645219b2ee8SDavid du Colombier Physseg *ps; 6463e12c5d1SDavid du Colombier 6474de34a7eSDavid du Colombier if(va != 0 && va >= USTKTOP) 6483e12c5d1SDavid du Colombier error(Ebadarg); 6493e12c5d1SDavid du Colombier 6503e12c5d1SDavid du Colombier validaddr((ulong)name, 1, 0); 6513e12c5d1SDavid du Colombier vmemchr(name, 0, ~0); 6523e12c5d1SDavid du Colombier 6533e12c5d1SDavid du Colombier for(sno = 0; sno < NSEG; sno++) 6547dd7cddfSDavid du Colombier if(p->seg[sno] == nil && sno != ESEG) 6553e12c5d1SDavid du Colombier break; 6563e12c5d1SDavid du Colombier 6573e12c5d1SDavid du Colombier if(sno == NSEG) 6583e12c5d1SDavid du Colombier error(Enovmem); 6593e12c5d1SDavid du Colombier 6609a747e4fSDavid du Colombier /* 6619a747e4fSDavid du Colombier * first look for a global segment with the 6629a747e4fSDavid du Colombier * same name 6639a747e4fSDavid du Colombier */ 6649a747e4fSDavid du Colombier if(_globalsegattach != nil){ 6659a747e4fSDavid du Colombier s = (*_globalsegattach)(p, name); 6669a747e4fSDavid du Colombier if(s != nil){ 6679a747e4fSDavid du Colombier p->seg[sno] = s; 6689a747e4fSDavid du Colombier return s->base; 6699a747e4fSDavid du Colombier } 6709a747e4fSDavid du Colombier } 6719a747e4fSDavid du Colombier 6723e12c5d1SDavid du Colombier len = PGROUND(len); 6737dd7cddfSDavid du Colombier if(len == 0) 6747dd7cddfSDavid du Colombier error(Ebadarg); 675219b2ee8SDavid du Colombier 6767dd7cddfSDavid du Colombier /* 6777dd7cddfSDavid du Colombier * Find a hole in the address space. 6787dd7cddfSDavid du Colombier * Starting at the lowest possible stack address - len, 6797dd7cddfSDavid du Colombier * check for an overlapping segment, and repeat at the 6807dd7cddfSDavid du Colombier * base of that segment - len until either a hole is found 681d1be6b08SDavid du Colombier * or the address space is exhausted. Ensure that we don't 682d1be6b08SDavid du Colombier * map the zero page. 6837dd7cddfSDavid du Colombier */ 684219b2ee8SDavid du Colombier if(va == 0) { 685d1be6b08SDavid du Colombier for (os = p->seg[SSEG]; os != nil; os = isoverlap(p, va, len)) { 6867dd7cddfSDavid du Colombier va = os->base; 687d1be6b08SDavid du Colombier if(len >= va) 6887dd7cddfSDavid du Colombier error(Enovmem); 689219b2ee8SDavid du Colombier va -= len; 6903e12c5d1SDavid du Colombier } 691d1be6b08SDavid du Colombier va &= ~(BY2PG-1); 692d1be6b08SDavid du Colombier } else { 693d1be6b08SDavid du Colombier va &= ~(BY2PG-1); 694d1be6b08SDavid du Colombier if(va == 0 || va >= USTKTOP) 695d1be6b08SDavid du Colombier error(Ebadarg); 696219b2ee8SDavid du Colombier } 697219b2ee8SDavid du Colombier 6987dd7cddfSDavid du Colombier if(isoverlap(p, va, len) != nil) 699219b2ee8SDavid du Colombier error(Esoverlap); 7003e12c5d1SDavid du Colombier 7013e12c5d1SDavid du Colombier for(ps = physseg; ps->name; ps++) 7023e12c5d1SDavid du Colombier if(strcmp(name, ps->name) == 0) 7033e12c5d1SDavid du Colombier goto found; 7043e12c5d1SDavid du Colombier 7053e12c5d1SDavid du Colombier error(Ebadarg); 7063e12c5d1SDavid du Colombier found: 7073e12c5d1SDavid du Colombier if(len > ps->size) 7083e12c5d1SDavid du Colombier error(Enovmem); 7093e12c5d1SDavid du Colombier 7107dd7cddfSDavid du Colombier attr &= ~SG_TYPE; /* Turn off what is not allowed */ 7113e12c5d1SDavid du Colombier attr |= ps->attr; /* Copy in defaults */ 7123e12c5d1SDavid du Colombier 7133e12c5d1SDavid du Colombier s = newseg(attr, va, len/BY2PG); 714219b2ee8SDavid du Colombier s->pseg = ps; 7157dd7cddfSDavid du Colombier p->seg[sno] = s; 7163e12c5d1SDavid du Colombier 717219b2ee8SDavid du Colombier return va; 7183e12c5d1SDavid du Colombier } 7193e12c5d1SDavid du Colombier 720219b2ee8SDavid du Colombier void 721219b2ee8SDavid du Colombier pteflush(Pte *pte, int s, int e) 722219b2ee8SDavid du Colombier { 723219b2ee8SDavid du Colombier int i; 724219b2ee8SDavid du Colombier Page *p; 725219b2ee8SDavid du Colombier 726219b2ee8SDavid du Colombier for(i = s; i < e; i++) { 727219b2ee8SDavid du Colombier p = pte->pages[i]; 728219b2ee8SDavid du Colombier if(pagedout(p) == 0) 729219b2ee8SDavid du Colombier memset(p->cachectl, PG_TXTFLUSH, sizeof(p->cachectl)); 730219b2ee8SDavid du Colombier } 731219b2ee8SDavid du Colombier } 732219b2ee8SDavid du Colombier 7333e12c5d1SDavid du Colombier long 7343e12c5d1SDavid du Colombier syssegflush(ulong *arg) 7357dd7cddfSDavid du Colombier { 7367dd7cddfSDavid du Colombier Segment *s; 737219b2ee8SDavid du Colombier ulong addr, l; 738219b2ee8SDavid du Colombier Pte *pte; 739219b2ee8SDavid du Colombier int chunk, ps, pe, len; 7403e12c5d1SDavid du Colombier 741219b2ee8SDavid du Colombier addr = arg[0]; 742219b2ee8SDavid du Colombier len = arg[1]; 743219b2ee8SDavid du Colombier 744219b2ee8SDavid du Colombier while(len > 0) { 7457dd7cddfSDavid du Colombier s = seg(up, addr, 1); 7463e12c5d1SDavid du Colombier if(s == 0) 7473e12c5d1SDavid du Colombier error(Ebadarg); 7483e12c5d1SDavid du Colombier 7493e12c5d1SDavid du Colombier s->flushme = 1; 750219b2ee8SDavid du Colombier more: 751219b2ee8SDavid du Colombier l = len; 752219b2ee8SDavid du Colombier if(addr+l > s->top) 753219b2ee8SDavid du Colombier l = s->top - addr; 7543e12c5d1SDavid du Colombier 755219b2ee8SDavid du Colombier ps = addr-s->base; 756219b2ee8SDavid du Colombier pte = s->map[ps/PTEMAPMEM]; 757219b2ee8SDavid du Colombier ps &= PTEMAPMEM-1; 758219b2ee8SDavid du Colombier pe = PTEMAPMEM; 759219b2ee8SDavid du Colombier if(pe-ps > l){ 760219b2ee8SDavid du Colombier pe = ps + l; 761219b2ee8SDavid du Colombier pe = (pe+BY2PG-1)&~(BY2PG-1); 7623e12c5d1SDavid du Colombier } 763219b2ee8SDavid du Colombier if(pe == ps) { 7643e12c5d1SDavid du Colombier qunlock(&s->lk); 765219b2ee8SDavid du Colombier error(Ebadarg); 766219b2ee8SDavid du Colombier } 767219b2ee8SDavid du Colombier 768219b2ee8SDavid du Colombier if(pte) 769219b2ee8SDavid du Colombier pteflush(pte, ps/BY2PG, pe/BY2PG); 770219b2ee8SDavid du Colombier 771219b2ee8SDavid du Colombier chunk = pe-ps; 772219b2ee8SDavid du Colombier len -= chunk; 773219b2ee8SDavid du Colombier addr += chunk; 774219b2ee8SDavid du Colombier 775219b2ee8SDavid du Colombier if(len > 0 && addr < s->top) 776219b2ee8SDavid du Colombier goto more; 777219b2ee8SDavid du Colombier 778219b2ee8SDavid du Colombier qunlock(&s->lk); 779219b2ee8SDavid du Colombier } 7803e12c5d1SDavid du Colombier flushmmu(); 7813e12c5d1SDavid du Colombier return 0; 7823e12c5d1SDavid du Colombier } 7837dd7cddfSDavid du Colombier 7847dd7cddfSDavid du Colombier void 7857dd7cddfSDavid du Colombier segclock(ulong pc) 7867dd7cddfSDavid du Colombier { 7877dd7cddfSDavid du Colombier Segment *s; 7887dd7cddfSDavid du Colombier 7897dd7cddfSDavid du Colombier s = up->seg[TSEG]; 7907dd7cddfSDavid du Colombier if(s == 0 || s->profile == 0) 7917dd7cddfSDavid du Colombier return; 7927dd7cddfSDavid du Colombier 7937dd7cddfSDavid du Colombier s->profile[0] += TK2MS(1); 7947dd7cddfSDavid du Colombier if(pc >= s->base && pc < s->top) { 7957dd7cddfSDavid du Colombier pc -= s->base; 7967dd7cddfSDavid du Colombier s->profile[pc>>LRESPROF] += TK2MS(1); 7977dd7cddfSDavid du Colombier } 7987dd7cddfSDavid du Colombier } 7993c2ddefeSDavid du Colombier 800