2 #include "../port/lib.h"
6 #include "../port/error.h"
9 * Attachable segment types
11 static Physseg physseg[10] = {
12 { SG_SHARED, "shared", 0, SEGMAXSIZE },
13 { SG_BSS, "memory", 0, SEGMAXSIZE },
17 static Lock physseglock;
20 #define ihash(s) imagealloc.hash[s%IHASHSIZE]
21 static struct Imagealloc
26 Image *hash[IHASHSIZE];
27 QLock ireclaim; /* mutex on reclaiming free images */
30 Segment* (*_globalsegattach)(Proc*, char*);
37 imagealloc.list = xalloc(conf.nimage*sizeof(Image));
38 if(imagealloc.list == nil)
39 panic("initseg: no memory for Image");
40 ie = &imagealloc.list[conf.nimage-1];
41 for(i = imagealloc.list; i < ie; i++)
44 imagealloc.free = imagealloc.list;
48 newseg(int type, uintptr base, ulong size)
53 if(size > (SEGMAPSIZE*PTEPERTAB))
56 s = malloc(sizeof(Segment));
62 s->top = base+(size*BY2PG);
64 s->sema.prev = &s->sema;
65 s->sema.next = &s->sema;
67 mapsize = ROUND(size, PTEPERTAB)/PTEPERTAB;
68 if(mapsize > nelem(s->ssegmap)){
69 s->map = malloc(mapsize*sizeof(Pte*));
78 s->mapsize = nelem(s->ssegmap);
104 } else if(decref(s) != 0)
107 emap = &s->map[s->mapsize];
108 for(pte = s->map; pte < emap; pte++)
112 if(s->map != s->ssegmap)
114 if(s->profile != nil)
121 relocateseg(Segment *s, uintptr offset)
126 emap = &s->map[s->mapsize];
127 for(pte = s->map; pte < emap; pte++) {
131 for(pg = (*pte)->first; pg <= pe; pg++) {
139 dupseg(Segment **seg, int segno, int share)
153 switch(s->type&SG_TYPE) {
154 case SG_TEXT: /* New segment shares pte set */
161 n = newseg(s->type, s->base, s->size);
164 case SG_BSS: /* Just copy on write */
167 n = newseg(s->type, s->base, s->size);
170 case SG_DATA: /* Copy on write plus demand load info */
180 n = newseg(s->type, s->base, s->size);
184 n->fstart = s->fstart;
189 for(i = 0; i < size; i++)
190 if((pte = s->map[i]) != nil)
191 n->map[i] = ptecpy(pte);
193 n->flushme = s->flushme;
208 segpage(Segment *s, Page *p)
214 if(p->va < s->base || p->va >= s->top)
217 soff = p->va - s->base;
218 pte = &s->map[soff/PTEMAPMEM];
219 if((etp = *pte) == nil)
220 *pte = etp = ptealloc();
222 pg = &etp->pages[(soff&(PTEMAPMEM-1))/BY2PG];
231 attachimage(int type, Chan *c, uintptr base, ulong len)
238 * Search the image cache for remains of the text from a previous
239 * or currently running incarnation
241 for(i = ihash(c->qid.path); i; i = i->hash) {
242 if(c->qid.path == i->qid.path) {
244 if(eqchantdqid(c, i->type, i->dev, i->qid, 0) && c->qid.type == i->qid.type)
250 /* dump pages of inactive images to free image structures */
251 while((i = imagealloc.free) == nil) {
253 if(imagereclaim(1000) == 0 && imagealloc.free == nil){
254 freebroken(); /* can use the memory */
255 resrcwait("no image after reclaim");
260 imagealloc.free = i->next;
267 l = &ihash(c->qid.path);
286 i->s = newseg(type, base, len);
297 imagereclaim(ulong pages)
299 static Image *i, *ie;
306 eqlock(&imagealloc.ireclaim);
309 ie = &imagealloc.list[conf.nimage];
312 for(j = 0; j < conf.nimage; j++, i++){
318 * if there are no free image structures, only
319 * reclaim pages from inactive images.
321 if(imagealloc.free != nil || i->ref == i->pgref){
322 np += pagereclaim(i, pages - np);
327 qunlock(&imagealloc.ireclaim);
349 * all remaining references to this image are from the
350 * page cache, so close the chan.
356 l = &ihash(i->qid.path);
357 mkqid(&i->qid, ~0, ~0, QTFILE);
361 for(f = *l; f != nil; f = f->hash) {
368 i->next = imagealloc.free;
374 ccloseq(c); /* does not block */
378 ibrk(uintptr addr, int seg)
395 /* We may start with the bss overlapping the data */
397 if(seg != BSEG || up->seg[DSEG] == nil || addr < up->seg[DSEG]->base) {
404 newtop = PGROUND(addr);
405 newsize = (newtop-s->base)/BY2PG;
406 if(newtop < s->top) {
408 * do not shrink a segment shared with other procs, as the
409 * to-be-freed address space may have been passed to the kernel
410 * already by another proc and is past the validaddr stage.
416 mfreeseg(s, newtop, (s->top-newtop)/BY2PG);
424 for(i = 0; i < NSEG; i++) {
426 if(ns == nil || ns == s)
428 if(newtop >= ns->base && newtop < ns->top) {
434 if(newsize > (SEGMAPSIZE*PTEPERTAB)) {
438 mapsize = ROUND(newsize, PTEPERTAB)/PTEPERTAB;
439 if(mapsize > s->mapsize){
440 map = malloc(mapsize*sizeof(Pte*));
445 memmove(map, s->map, s->mapsize*sizeof(Pte*));
446 if(s->map != s->ssegmap)
449 s->mapsize = mapsize;
459 * called with s locked
462 mcountseg(Segment *s)
468 if((s->type&SG_TYPE) == SG_PHYSICAL)
472 emap = &s->map[s->mapsize];
473 for(pte = s->map; pte < emap; pte++){
477 for(pg = (*pte)->first; pg <= pe; pg++)
485 * called with s locked
488 mfreeseg(Segment *s, uintptr start, ulong pages)
497 switch(s->type&SG_TYPE){
504 * we have to make sure other processors flush the
505 * entry from their TLBs before the page is freed.
511 pte = &s->map[off/PTEMAPMEM];
512 off = (off&(PTEMAPMEM-1))/BY2PG;
513 for(emap = &s->map[s->mapsize]; pte < emap; pte++, off = 0) {
515 off = PTEPERTAB - off;
521 pg = &(*pte)->pages[off];
522 for(pe = &(*pte)->pages[PTEPERTAB]; pg < pe; pg++) {
534 isoverlap(Proc *p, uintptr va, uintptr len)
541 for(i = 0; i < NSEG; i++) {
545 if((newtop > ns->base && newtop <= ns->top) ||
546 (va >= ns->base && va < ns->top))
553 addphysseg(Physseg* new)
558 * Check not already entered and there is room
559 * for a new entry and the terminating null entry.
562 for(ps = physseg; ps->name; ps++){
563 if(strcmp(ps->name, new->name) == 0){
564 unlock(&physseglock);
568 if(ps-physseg >= nelem(physseg)-2){
569 unlock(&physseglock);
573 unlock(&physseglock);
579 isphysseg(char *name)
585 for(ps = physseg; ps->name; ps++){
586 if(strcmp(ps->name, name) == 0){
591 unlock(&physseglock);
596 segattach(Proc *p, ulong attr, char *name, uintptr va, uintptr len)
602 if(va != 0 && va >= USTKTOP)
605 validaddr((uintptr)name, 1, 0);
606 vmemchr(name, 0, ~0);
608 for(sno = 0; sno < NSEG; sno++)
609 if(p->seg[sno] == nil && sno != ESEG)
616 * first look for a global segment with the
619 if(_globalsegattach != nil){
620 s = (*_globalsegattach)(p, name);
627 /* round up va+len */
628 len += va & (BY2PG-1);
635 * Find a hole in the address space.
636 * Starting at the lowest possible stack address - len,
637 * check for an overlapping segment, and repeat at the
638 * base of that segment - len until either a hole is found
639 * or the address space is exhausted. Ensure that we don't
643 for (os = p->seg[SSEG]; os != nil; os = isoverlap(p, va, len)) {
652 if(va == 0 || (va+len) > USTKTOP || (va+len) < va)
655 if(isoverlap(p, va, len) != nil)
658 for(ps = physseg; ps->name; ps++)
659 if(strcmp(name, ps->name) == 0)
667 attr &= ~SG_TYPE; /* Turn off what is not allowed */
668 attr |= ps->attr; /* Copy in defaults */
670 s = newseg(attr, va, len/BY2PG);
678 segflush(void *va, uintptr len)
680 uintptr from, to, off;
693 s = seg(up, from, 1);
699 len = (s->top < to ? s->top : to) - from;
701 pte = s->map[off/PTEMAPMEM];
703 if(off+len > PTEMAPMEM)
707 pg = &pte->pages[off/BY2PG];
711 (*pg)->txtflush = ~0;
717 if(from < to && from < s->top)
725 syssegflush(va_list list)
730 va = va_arg(list, void*);
731 len = va_arg(list, ulong);
743 if(s == nil || s->profile == nil)
746 s->profile[0] += TK2MS(1);
747 if(pc >= s->base && pc < s->top) {
749 s->profile[pc>>LRESPROF] += TK2MS(1);
758 ps = newseg(SG_DATA, s->base, s->size);
759 ps->image = s->image;
761 ps->fstart = s->fstart;
775 ps = newseg(SG_TEXT, s->base, s->size);
776 ps->image = s->image;
778 ps->fstart = s->fstart;
786 /* commands to segmentioproc */
798 return sio->cmd == Cnone;
802 docmd(Segio *sio, int cmd)
808 wakeup(&sio->cmdwait);
809 sleep(&sio->replywait, cmddone, sio);
820 return sio->cmd != Cnone;
824 segmentioproc(void *arg)
830 for(sno = 0; sno < NSEG; sno++)
831 if(up->seg[sno] == nil && sno != ESEG)
834 panic("segmentkproc");
838 up->seg[sno] = sio->s;
842 for(done = 0; !done;){
843 sleep(&sio->cmdwait, cmdready, sio);
845 sio->err = up->errstr;
847 if(sio->s != nil && up->seg[sno] != sio->s){
848 putseg(up->seg[sno]);
850 up->seg[sno] = sio->s;
855 memmove(sio->data, sio->addr, sio->dlen);
858 memmove(sio->addr, sio->data, sio->dlen);
860 segflush(sio->addr, sio->dlen);
869 wakeup(&sio->replywait);
876 segio(Segio *sio, Segment *s, void *a, long n, vlong off, int read)
883 m = s->top - s->base;
884 if(off < 0 || off >= m){
895 if((uintptr)a < KZERO) {
923 kproc("segmentio", segmentioproc, sio);
925 sio->addr = (char*)s->base + off;
928 docmd(sio, read ? Cread : Cwrite);