19ef1f84bSDavid du Colombier #include "u.h"
29ef1f84bSDavid du Colombier #include "../port/lib.h"
39ef1f84bSDavid du Colombier #include "mem.h"
49ef1f84bSDavid du Colombier #include "dat.h"
59ef1f84bSDavid du Colombier #include "fns.h"
69ef1f84bSDavid du Colombier #include "../port/error.h"
79ef1f84bSDavid du Colombier
89ef1f84bSDavid du Colombier Segment *
newseg(int type,uintptr base,uintptr top)99ef1f84bSDavid du Colombier newseg(int type, uintptr base, uintptr top)
109ef1f84bSDavid du Colombier {
119ef1f84bSDavid du Colombier Segment *s;
129ef1f84bSDavid du Colombier int mapsize;
139ef1f84bSDavid du Colombier usize size;
149ef1f84bSDavid du Colombier
159ef1f84bSDavid du Colombier if((base|top) & (PGSZ-1))
169ef1f84bSDavid du Colombier panic("newseg");
179ef1f84bSDavid du Colombier
189ef1f84bSDavid du Colombier size = (top-base)/PGSZ;
199ef1f84bSDavid du Colombier if(size > (SEGMAPSIZE*PTEPERTAB))
209ef1f84bSDavid du Colombier error(Enovmem);
219ef1f84bSDavid du Colombier
229ef1f84bSDavid du Colombier s = smalloc(sizeof(Segment));
239ef1f84bSDavid du Colombier s->ref = 1;
249ef1f84bSDavid du Colombier s->type = type;
259ef1f84bSDavid du Colombier s->base = base;
269ef1f84bSDavid du Colombier s->top = top;
279ef1f84bSDavid du Colombier s->size = size;
289ef1f84bSDavid du Colombier s->lg2pgsize = PGSHFT;
299ef1f84bSDavid du Colombier s->ptemapmem = PTEPERTAB<<s->lg2pgsize;
309ef1f84bSDavid du Colombier s->sema.prev = &s->sema;
319ef1f84bSDavid du Colombier s->sema.next = &s->sema;
329ef1f84bSDavid du Colombier
339ef1f84bSDavid du Colombier mapsize = HOWMANY(size, PTEPERTAB);
349ef1f84bSDavid du Colombier if(mapsize > nelem(s->ssegmap)){
359ef1f84bSDavid du Colombier mapsize *= 2;
369ef1f84bSDavid du Colombier if(mapsize > SEGMAPSIZE)
379ef1f84bSDavid du Colombier mapsize = SEGMAPSIZE;
389ef1f84bSDavid du Colombier s->map = smalloc(mapsize*sizeof(Pte*));
399ef1f84bSDavid du Colombier s->mapsize = mapsize;
409ef1f84bSDavid du Colombier }
419ef1f84bSDavid du Colombier else{
429ef1f84bSDavid du Colombier s->map = s->ssegmap;
439ef1f84bSDavid du Colombier s->mapsize = nelem(s->ssegmap);
449ef1f84bSDavid du Colombier }
459ef1f84bSDavid du Colombier
469ef1f84bSDavid du Colombier return s;
479ef1f84bSDavid du Colombier }
489ef1f84bSDavid du Colombier
499ef1f84bSDavid du Colombier void
putseg(Segment * s)509ef1f84bSDavid du Colombier putseg(Segment *s)
519ef1f84bSDavid du Colombier {
529ef1f84bSDavid du Colombier Pte **pp, **emap;
539ef1f84bSDavid du Colombier Image *i;
549ef1f84bSDavid du Colombier
554498a243SDavid du Colombier if(s == nil)
569ef1f84bSDavid du Colombier return;
579ef1f84bSDavid du Colombier
589ef1f84bSDavid du Colombier i = s->image;
594498a243SDavid du Colombier if(i != nil) {
609ef1f84bSDavid du Colombier lock(i);
619ef1f84bSDavid du Colombier lock(s);
629ef1f84bSDavid du Colombier if(i->s == s && s->ref == 1)
639ef1f84bSDavid du Colombier i->s = 0;
649ef1f84bSDavid du Colombier unlock(i);
659ef1f84bSDavid du Colombier }
669ef1f84bSDavid du Colombier else
679ef1f84bSDavid du Colombier lock(s);
689ef1f84bSDavid du Colombier
699ef1f84bSDavid du Colombier s->ref--;
709ef1f84bSDavid du Colombier if(s->ref != 0) {
719ef1f84bSDavid du Colombier unlock(s);
729ef1f84bSDavid du Colombier return;
739ef1f84bSDavid du Colombier }
749ef1f84bSDavid du Colombier unlock(s);
759ef1f84bSDavid du Colombier
769ef1f84bSDavid du Colombier qlock(&s->lk);
779ef1f84bSDavid du Colombier if(i)
789ef1f84bSDavid du Colombier putimage(i);
799ef1f84bSDavid du Colombier
809ef1f84bSDavid du Colombier emap = &s->map[s->mapsize];
819ef1f84bSDavid du Colombier for(pp = s->map; pp < emap; pp++)
824498a243SDavid du Colombier if(*pp != nil)
839ef1f84bSDavid du Colombier freepte(s, *pp);
849ef1f84bSDavid du Colombier
859ef1f84bSDavid du Colombier qunlock(&s->lk);
869ef1f84bSDavid du Colombier if(s->map != s->ssegmap)
879ef1f84bSDavid du Colombier free(s->map);
884498a243SDavid du Colombier if(s->profile != nil)
899ef1f84bSDavid du Colombier free(s->profile);
909ef1f84bSDavid du Colombier free(s);
919ef1f84bSDavid du Colombier }
929ef1f84bSDavid du Colombier
939ef1f84bSDavid du Colombier void
relocateseg(Segment * s,uintptr offset)949ef1f84bSDavid du Colombier relocateseg(Segment *s, uintptr offset)
959ef1f84bSDavid du Colombier {
969ef1f84bSDavid du Colombier Page **pg, *x;
979ef1f84bSDavid du Colombier Pte *pte, **p, **endpte;
989ef1f84bSDavid du Colombier
999ef1f84bSDavid du Colombier endpte = &s->map[s->mapsize];
1009ef1f84bSDavid du Colombier for(p = s->map; p < endpte; p++) {
1019ef1f84bSDavid du Colombier if(*p == 0)
1029ef1f84bSDavid du Colombier continue;
1039ef1f84bSDavid du Colombier pte = *p;
1049ef1f84bSDavid du Colombier for(pg = pte->first; pg <= pte->last; pg++) {
1059ef1f84bSDavid du Colombier if(x = *pg)
1069ef1f84bSDavid du Colombier x->va += offset;
1079ef1f84bSDavid du Colombier }
1089ef1f84bSDavid du Colombier }
1099ef1f84bSDavid du Colombier }
1109ef1f84bSDavid du Colombier
1119ef1f84bSDavid du Colombier Segment*
dupseg(Segment ** seg,int segno,int share)1129ef1f84bSDavid du Colombier dupseg(Segment **seg, int segno, int share)
1139ef1f84bSDavid du Colombier {
1149ef1f84bSDavid du Colombier int i, size;
1159ef1f84bSDavid du Colombier Pte *pte;
1169ef1f84bSDavid du Colombier Segment *n, *s;
1179ef1f84bSDavid du Colombier
1189ef1f84bSDavid du Colombier SET(n);
1199ef1f84bSDavid du Colombier s = seg[segno];
1209ef1f84bSDavid du Colombier
1219ef1f84bSDavid du Colombier qlock(&s->lk);
1229ef1f84bSDavid du Colombier if(waserror()){
1239ef1f84bSDavid du Colombier qunlock(&s->lk);
1249ef1f84bSDavid du Colombier nexterror();
1259ef1f84bSDavid du Colombier }
1269ef1f84bSDavid du Colombier switch(s->type&SG_TYPE) {
1279ef1f84bSDavid du Colombier case SG_TEXT: /* New segment shares pte set */
1289ef1f84bSDavid du Colombier case SG_SHARED:
1299ef1f84bSDavid du Colombier case SG_PHYSICAL:
1309ef1f84bSDavid du Colombier goto sameseg;
1319ef1f84bSDavid du Colombier
1329ef1f84bSDavid du Colombier case SG_STACK:
1339ef1f84bSDavid du Colombier n = newseg(s->type, s->base, s->top);
1349ef1f84bSDavid du Colombier break;
1359ef1f84bSDavid du Colombier
1369ef1f84bSDavid du Colombier case SG_BSS: /* Just copy on write */
1379ef1f84bSDavid du Colombier if(share)
1389ef1f84bSDavid du Colombier goto sameseg;
1399ef1f84bSDavid du Colombier n = newseg(s->type, s->base, s->top);
1409ef1f84bSDavid du Colombier break;
1419ef1f84bSDavid du Colombier
1429ef1f84bSDavid du Colombier case SG_DATA: /* Copy on write plus demand load info */
1439ef1f84bSDavid du Colombier if(segno == TSEG){
1449ef1f84bSDavid du Colombier poperror();
1459ef1f84bSDavid du Colombier qunlock(&s->lk);
1469ef1f84bSDavid du Colombier return data2txt(s);
1479ef1f84bSDavid du Colombier }
1489ef1f84bSDavid du Colombier
1499ef1f84bSDavid du Colombier if(share)
1509ef1f84bSDavid du Colombier goto sameseg;
1519ef1f84bSDavid du Colombier n = newseg(s->type, s->base, s->top);
1529ef1f84bSDavid du Colombier
1539ef1f84bSDavid du Colombier incref(s->image);
1549ef1f84bSDavid du Colombier n->image = s->image;
1559ef1f84bSDavid du Colombier n->fstart = s->fstart;
1569ef1f84bSDavid du Colombier n->flen = s->flen;
157a8c2c03cSDavid du Colombier n->lg2pgsize = s->lg2pgsize;
158*094d6818SDavid du Colombier n->color = s->color;
1599ef1f84bSDavid du Colombier break;
1609ef1f84bSDavid du Colombier }
1619ef1f84bSDavid du Colombier size = s->mapsize;
1629ef1f84bSDavid du Colombier for(i = 0; i < size; i++)
1634498a243SDavid du Colombier if((pte = s->map[i]) != nil)
1649ef1f84bSDavid du Colombier n->map[i] = ptecpy(pte);
1659ef1f84bSDavid du Colombier
1669ef1f84bSDavid du Colombier n->flushme = s->flushme;
1679ef1f84bSDavid du Colombier if(s->ref > 1)
1689ef1f84bSDavid du Colombier procflushseg(s);
1699ef1f84bSDavid du Colombier poperror();
1709ef1f84bSDavid du Colombier qunlock(&s->lk);
1719ef1f84bSDavid du Colombier return n;
1729ef1f84bSDavid du Colombier
1739ef1f84bSDavid du Colombier sameseg:
1749ef1f84bSDavid du Colombier incref(s);
1759ef1f84bSDavid du Colombier poperror();
1769ef1f84bSDavid du Colombier qunlock(&s->lk);
1779ef1f84bSDavid du Colombier return s;
1789ef1f84bSDavid du Colombier }
1799ef1f84bSDavid du Colombier
1809ef1f84bSDavid du Colombier void
segpage(Segment * s,Page * p)1819ef1f84bSDavid du Colombier segpage(Segment *s, Page *p)
1829ef1f84bSDavid du Colombier {
1839ef1f84bSDavid du Colombier Pte **pte;
1849ef1f84bSDavid du Colombier uintptr soff;
1859ef1f84bSDavid du Colombier Page **pg;
1869ef1f84bSDavid du Colombier
187*094d6818SDavid du Colombier if(s->color == NOCOLOR)
188*094d6818SDavid du Colombier s->color = p->color;
189*094d6818SDavid du Colombier
1909ef1f84bSDavid du Colombier if(p->va < s->base || p->va >= s->top)
1919ef1f84bSDavid du Colombier panic("segpage");
1929ef1f84bSDavid du Colombier
1939ef1f84bSDavid du Colombier soff = p->va - s->base;
1949ef1f84bSDavid du Colombier pte = &s->map[soff/s->ptemapmem];
1959ef1f84bSDavid du Colombier if(*pte == 0)
1969ef1f84bSDavid du Colombier *pte = ptealloc();
1979ef1f84bSDavid du Colombier
1989ef1f84bSDavid du Colombier pg = &(*pte)->pages[(soff&(s->ptemapmem-1))>>s->lg2pgsize];
1999ef1f84bSDavid du Colombier *pg = p;
2009ef1f84bSDavid du Colombier if(pg < (*pte)->first)
2019ef1f84bSDavid du Colombier (*pte)->first = pg;
2029ef1f84bSDavid du Colombier if(pg > (*pte)->last)
2039ef1f84bSDavid du Colombier (*pte)->last = pg;
2049ef1f84bSDavid du Colombier }
2059ef1f84bSDavid du Colombier
2069ef1f84bSDavid du Colombier /*
2079ef1f84bSDavid du Colombier * called with s->lk locked
2089ef1f84bSDavid du Colombier */
2099ef1f84bSDavid du Colombier void
mfreeseg(Segment * s,uintptr start,uintptr top)2109ef1f84bSDavid du Colombier mfreeseg(Segment *s, uintptr start, uintptr top)
2119ef1f84bSDavid du Colombier {
2129ef1f84bSDavid du Colombier int i, j, size;
2139ef1f84bSDavid du Colombier usize pages;
2149ef1f84bSDavid du Colombier uintptr soff;
2159ef1f84bSDavid du Colombier Page *pg;
2169ef1f84bSDavid du Colombier Page *list;
2179ef1f84bSDavid du Colombier
2189ef1f84bSDavid du Colombier pages = (top-start)>>s->lg2pgsize;
2199ef1f84bSDavid du Colombier soff = start-s->base;
2209ef1f84bSDavid du Colombier j = (soff&(s->ptemapmem-1))>>s->lg2pgsize;
2219ef1f84bSDavid du Colombier
2229ef1f84bSDavid du Colombier size = s->mapsize;
2239ef1f84bSDavid du Colombier list = nil;
2249ef1f84bSDavid du Colombier for(i = soff/s->ptemapmem; i < size; i++) {
2259ef1f84bSDavid du Colombier if(pages <= 0)
2269ef1f84bSDavid du Colombier break;
2279ef1f84bSDavid du Colombier if(s->map[i] == 0) {
2289ef1f84bSDavid du Colombier pages -= PTEPERTAB-j;
2299ef1f84bSDavid du Colombier j = 0;
2309ef1f84bSDavid du Colombier continue;
2319ef1f84bSDavid du Colombier }
2329ef1f84bSDavid du Colombier while(j < PTEPERTAB) {
2339ef1f84bSDavid du Colombier pg = s->map[i]->pages[j];
2349ef1f84bSDavid du Colombier /*
2359ef1f84bSDavid du Colombier * We want to zero s->map[i]->page[j] and putpage(pg),
2369ef1f84bSDavid du Colombier * but we have to make sure other processors flush the
2379ef1f84bSDavid du Colombier * entry from their TLBs before the page is freed.
2389ef1f84bSDavid du Colombier * We construct a list of the pages to be freed, zero
2399ef1f84bSDavid du Colombier * the entries, then (below) call procflushseg, and call
2409ef1f84bSDavid du Colombier * putpage on the whole list. If swapping were implemented,
2419ef1f84bSDavid du Colombier * paged-out pages can't be in a TLB and could be disposed of here.
2429ef1f84bSDavid du Colombier */
2439ef1f84bSDavid du Colombier if(pg != nil){
2449ef1f84bSDavid du Colombier pg->next = list;
2459ef1f84bSDavid du Colombier list = pg;
2469ef1f84bSDavid du Colombier s->map[i]->pages[j] = nil;
2479ef1f84bSDavid du Colombier }
2489ef1f84bSDavid du Colombier if(--pages == 0)
2499ef1f84bSDavid du Colombier goto out;
2509ef1f84bSDavid du Colombier j++;
2519ef1f84bSDavid du Colombier }
2529ef1f84bSDavid du Colombier j = 0;
2539ef1f84bSDavid du Colombier }
2549ef1f84bSDavid du Colombier out:
2559ef1f84bSDavid du Colombier /* flush this seg in all other processes */
2569ef1f84bSDavid du Colombier if(s->ref > 1)
2579ef1f84bSDavid du Colombier procflushseg(s);
2589ef1f84bSDavid du Colombier
2599ef1f84bSDavid du Colombier /* free the pages */
2609ef1f84bSDavid du Colombier for(pg = list; pg != nil; pg = list){
2619ef1f84bSDavid du Colombier list = list->next;
2629ef1f84bSDavid du Colombier putpage(pg);
2639ef1f84bSDavid du Colombier }
2649ef1f84bSDavid du Colombier }
2659ef1f84bSDavid du Colombier
2669ef1f84bSDavid du Colombier Segment*
isoverlap(Proc * p,uintptr va,usize len)2679ef1f84bSDavid du Colombier isoverlap(Proc* p, uintptr va, usize len)
2689ef1f84bSDavid du Colombier {
2699ef1f84bSDavid du Colombier int i;
2709ef1f84bSDavid du Colombier Segment *ns;
2719ef1f84bSDavid du Colombier uintptr newtop;
2729ef1f84bSDavid du Colombier
2739ef1f84bSDavid du Colombier newtop = va+len;
2749ef1f84bSDavid du Colombier for(i = 0; i < NSEG; i++) {
2759ef1f84bSDavid du Colombier ns = p->seg[i];
2764498a243SDavid du Colombier if(ns == nil)
2779ef1f84bSDavid du Colombier continue;
2781105a4a2SDavid du Colombier if(newtop > ns->base && va < ns->top)
2799ef1f84bSDavid du Colombier return ns;
2809ef1f84bSDavid du Colombier }
2819ef1f84bSDavid du Colombier return nil;
2829ef1f84bSDavid du Colombier }
2839ef1f84bSDavid du Colombier
2849ef1f84bSDavid du Colombier void
segclock(uintptr pc)2859ef1f84bSDavid du Colombier segclock(uintptr pc)
2869ef1f84bSDavid du Colombier {
2879ef1f84bSDavid du Colombier Segment *s;
2889ef1f84bSDavid du Colombier
2899ef1f84bSDavid du Colombier s = up->seg[TSEG];
2904498a243SDavid du Colombier if(s == nil || s->profile == nil)
2919ef1f84bSDavid du Colombier return;
2929ef1f84bSDavid du Colombier
2939ef1f84bSDavid du Colombier s->profile[0] += TK2MS(1);
2949ef1f84bSDavid du Colombier if(pc >= s->base && pc < s->top) {
2959ef1f84bSDavid du Colombier pc -= s->base;
2969ef1f84bSDavid du Colombier s->profile[pc>>LRESPROF] += TK2MS(1);
2979ef1f84bSDavid du Colombier }
2989ef1f84bSDavid du Colombier }
299