segment.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "../port/error.h"
  7. static void imagereclaim(void);
  8. static void imagechanreclaim(void);
  9. #include "io.h"
  10. /*
  11. * Attachable segment types
  12. */
  13. static Physseg physseg[10] = {
  14. { SG_SHARED, "shared", 0, SEGMAXSIZE, 0, 0 },
  15. { SG_BSS, "memory", 0, SEGMAXSIZE, 0, 0 },
  16. { 0, 0, 0, 0, 0, 0 },
  17. };
  18. static Lock physseglock;
  19. #define NFREECHAN 64
  20. #define IHASHSIZE 64
  21. #define ihash(s) imagealloc.hash[s%IHASHSIZE]
  22. static struct Imagealloc
  23. {
  24. Lock;
  25. Image *free;
  26. Image *hash[IHASHSIZE];
  27. QLock ireclaim; /* mutex on reclaiming free images */
  28. Chan **freechan; /* free image channels */
  29. int nfreechan; /* number of free channels */
  30. int szfreechan; /* size of freechan array */
  31. QLock fcreclaim; /* mutex on reclaiming free channels */
  32. }imagealloc;
  33. Segment* (*_globalsegattach)(Proc*, char*);
  34. void
  35. initseg(void)
  36. {
  37. Image *i, *ie;
  38. imagealloc.free = xalloc(conf.nimage*sizeof(Image));
  39. ie = &imagealloc.free[conf.nimage-1];
  40. for(i = imagealloc.free; i < ie; i++)
  41. i->next = i+1;
  42. i->next = 0;
  43. imagealloc.freechan = malloc(NFREECHAN * sizeof(Chan*));
  44. imagealloc.szfreechan = NFREECHAN;
  45. }
  46. Segment *
  47. newseg(int type, ulong base, ulong size)
  48. {
  49. Segment *s;
  50. int mapsize;
  51. if(size > (SEGMAPSIZE*PTEPERTAB))
  52. error(Enovmem);
  53. if(swapfull())
  54. error(Enoswap);
  55. s = smalloc(sizeof(Segment));
  56. s->ref = 1;
  57. s->type = type;
  58. s->base = base;
  59. s->top = base+(size*BY2PG);
  60. s->size = size;
  61. mapsize = ROUND(size, PTEPERTAB)/PTEPERTAB;
  62. if(mapsize > nelem(s->ssegmap)){
  63. mapsize *= 2;
  64. if(mapsize > (SEGMAPSIZE*PTEPERTAB))
  65. mapsize = (SEGMAPSIZE*PTEPERTAB);
  66. s->map = smalloc(mapsize*sizeof(Pte*));
  67. s->mapsize = mapsize;
  68. }
  69. else{
  70. s->map = s->ssegmap;
  71. s->mapsize = nelem(s->ssegmap);
  72. }
  73. return s;
  74. }
  75. void
  76. putseg(Segment *s)
  77. {
  78. Pte **pp, **emap;
  79. Image *i;
  80. if(s == 0)
  81. return;
  82. i = s->image;
  83. if(i != 0) {
  84. lock(i);
  85. lock(s);
  86. if(i->s == s && s->ref == 1)
  87. i->s = 0;
  88. unlock(i);
  89. }
  90. else
  91. lock(s);
  92. s->ref--;
  93. if(s->ref != 0) {
  94. unlock(s);
  95. return;
  96. }
  97. unlock(s);
  98. qlock(&s->lk);
  99. if(i)
  100. putimage(i);
  101. emap = &s->map[s->mapsize];
  102. for(pp = s->map; pp < emap; pp++)
  103. if(*pp)
  104. freepte(s, *pp);
  105. qunlock(&s->lk);
  106. if(s->map != s->ssegmap)
  107. free(s->map);
  108. if(s->profile != 0)
  109. free(s->profile);
  110. free(s);
  111. }
  112. void
  113. relocateseg(Segment *s, ulong offset)
  114. {
  115. Page **pg, *x;
  116. Pte *pte, **p, **endpte;
  117. endpte = &s->map[s->mapsize];
  118. for(p = s->map; p < endpte; p++) {
  119. if(*p == 0)
  120. continue;
  121. pte = *p;
  122. for(pg = pte->first; pg <= pte->last; pg++) {
  123. if(x = *pg)
  124. x->va += offset;
  125. }
  126. }
  127. }
  128. Segment*
  129. dupseg(Segment **seg, int segno, int share)
  130. {
  131. int i, size;
  132. Pte *pte;
  133. Segment *n, *s;
  134. SET(n);
  135. s = seg[segno];
  136. qlock(&s->lk);
  137. if(waserror()){
  138. qunlock(&s->lk);
  139. nexterror();
  140. }
  141. switch(s->type&SG_TYPE) {
  142. case SG_TEXT: /* New segment shares pte set */
  143. case SG_SHARED:
  144. case SG_PHYSICAL:
  145. goto sameseg;
  146. case SG_STACK:
  147. n = newseg(s->type, s->base, s->size);
  148. break;
  149. case SG_BSS: /* Just copy on write */
  150. if(share)
  151. goto sameseg;
  152. n = newseg(s->type, s->base, s->size);
  153. break;
  154. case SG_DATA: /* Copy on write plus demand load info */
  155. if(segno == TSEG){
  156. poperror();
  157. qunlock(&s->lk);
  158. return data2txt(s);
  159. }
  160. if(share)
  161. goto sameseg;
  162. n = newseg(s->type, s->base, s->size);
  163. incref(s->image);
  164. n->image = s->image;
  165. n->fstart = s->fstart;
  166. n->flen = s->flen;
  167. break;
  168. }
  169. size = s->mapsize;
  170. for(i = 0; i < size; i++)
  171. if(pte = s->map[i])
  172. n->map[i] = ptecpy(pte);
  173. n->flushme = s->flushme;
  174. if(s->ref > 1)
  175. procflushseg(s);
  176. poperror();
  177. qunlock(&s->lk);
  178. return n;
  179. sameseg:
  180. incref(s);
  181. poperror();
  182. qunlock(&s->lk);
  183. return s;
  184. }
  185. void
  186. segpage(Segment *s, Page *p)
  187. {
  188. Pte **pte;
  189. ulong off;
  190. Page **pg;
  191. if(p->va < s->base || p->va >= s->top)
  192. panic("segpage");
  193. off = p->va - s->base;
  194. pte = &s->map[off/PTEMAPMEM];
  195. if(*pte == 0)
  196. *pte = ptealloc();
  197. pg = &(*pte)->pages[(off&(PTEMAPMEM-1))/BY2PG];
  198. *pg = p;
  199. if(pg < (*pte)->first)
  200. (*pte)->first = pg;
  201. if(pg > (*pte)->last)
  202. (*pte)->last = pg;
  203. }
  204. Image*
  205. attachimage(int type, Chan *c, ulong base, ulong len)
  206. {
  207. Image *i, **l;
  208. /* reclaim any free channels from reclaimed segments */
  209. if(imagealloc.nfreechan)
  210. imagechanreclaim();
  211. lock(&imagealloc);
  212. /*
  213. * Search the image cache for remains of the text from a previous
  214. * or currently running incarnation
  215. */
  216. for(i = ihash(c->qid.path); i; i = i->hash) {
  217. if(c->qid.path == i->qid.path) {
  218. lock(i);
  219. if(eqqid(c->qid, i->qid) &&
  220. eqqid(c->mqid, i->mqid) &&
  221. c->mchan == i->mchan &&
  222. c->type == i->type) {
  223. goto found;
  224. }
  225. unlock(i);
  226. }
  227. }
  228. /*
  229. * imagereclaim dumps pages from the free list which are cached by image
  230. * structures. This should free some image structures.
  231. */
  232. while(!(i = imagealloc.free)) {
  233. unlock(&imagealloc);
  234. imagereclaim();
  235. sched();
  236. lock(&imagealloc);
  237. }
  238. imagealloc.free = i->next;
  239. lock(i);
  240. incref(c);
  241. i->c = c;
  242. i->type = c->type;
  243. i->qid = c->qid;
  244. i->mqid = c->mqid;
  245. i->mchan = c->mchan;
  246. l = &ihash(c->qid.path);
  247. i->hash = *l;
  248. *l = i;
  249. found:
  250. unlock(&imagealloc);
  251. if(i->s == 0) {
  252. /* Disaster after commit in exec */
  253. if(waserror()) {
  254. unlock(i);
  255. pexit(Enovmem, 1);
  256. }
  257. i->s = newseg(type, base, len);
  258. i->s->image = i;
  259. i->ref++;
  260. poperror();
  261. }
  262. else
  263. incref(i->s);
  264. return i;
  265. }
  266. static struct {
  267. int calls; /* times imagereclaim was called */
  268. int loops; /* times the main loop was run */
  269. uvlong ticks; /* total time in the main loop */
  270. uvlong maxt; /* longest time in main loop */
  271. } irstats;
  272. static void
  273. imagereclaim(void)
  274. {
  275. Page *p;
  276. uvlong ticks;
  277. irstats.calls++;
  278. /* Somebody is already cleaning the page cache */
  279. if(!canqlock(&imagealloc.ireclaim))
  280. return;
  281. lock(&palloc);
  282. ticks = fastticks(nil);
  283. for(p = palloc.head; p; p = p->next) {
  284. if(p->ref == 0 && p->image && canlock(p)) {
  285. if(p->ref == 0)
  286. uncachepage(p);
  287. unlock(p);
  288. }
  289. }
  290. ticks = fastticks(nil) - ticks;
  291. unlock(&palloc);
  292. irstats.loops++;
  293. irstats.ticks += ticks;
  294. if(ticks > irstats.maxt)
  295. irstats.maxt = ticks;
  296. //print("T%llud+", ticks);
  297. qunlock(&imagealloc.ireclaim);
  298. }
  299. /*
  300. * since close can block, this has to be called outside of
  301. * spin locks.
  302. */
  303. static void
  304. imagechanreclaim(void)
  305. {
  306. Chan *c;
  307. /* Somebody is already cleaning the image chans */
  308. if(!canqlock(&imagealloc.fcreclaim))
  309. return;
  310. /*
  311. * We don't have to recheck that nfreechan > 0 after we
  312. * acquire the lock, because we're the only ones who decrement
  313. * it (the other lock contender increments it), and there's only
  314. * one of us thanks to the qlock above.
  315. */
  316. while(imagealloc.nfreechan > 0){
  317. lock(&imagealloc);
  318. imagealloc.nfreechan--;
  319. c = imagealloc.freechan[imagealloc.nfreechan];
  320. unlock(&imagealloc);
  321. cclose(c);
  322. }
  323. qunlock(&imagealloc.fcreclaim);
  324. }
  325. void
  326. putimage(Image *i)
  327. {
  328. Chan *c, **cp;
  329. Image *f, **l;
  330. if(i->notext)
  331. return;
  332. lock(i);
  333. if(--i->ref == 0) {
  334. l = &ihash(i->qid.path);
  335. mkqid(&i->qid, ~0, ~0, QTFILE);
  336. unlock(i);
  337. c = i->c;
  338. lock(&imagealloc);
  339. for(f = *l; f; f = f->hash) {
  340. if(f == i) {
  341. *l = i->hash;
  342. break;
  343. }
  344. l = &f->hash;
  345. }
  346. i->next = imagealloc.free;
  347. imagealloc.free = i;
  348. /* defer freeing channel till we're out of spin lock's */
  349. if(imagealloc.nfreechan == imagealloc.szfreechan){
  350. imagealloc.szfreechan += NFREECHAN;
  351. cp = malloc(imagealloc.szfreechan*sizeof(Chan*));
  352. if(cp == nil)
  353. panic("putimage");
  354. memmove(cp, imagealloc.freechan, imagealloc.nfreechan*sizeof(Chan*));
  355. free(imagealloc.freechan);
  356. imagealloc.freechan = cp;
  357. }
  358. imagealloc.freechan[imagealloc.nfreechan++] = c;
  359. unlock(&imagealloc);
  360. return;
  361. }
  362. unlock(i);
  363. }
  364. long
  365. ibrk(ulong addr, int seg)
  366. {
  367. Segment *s, *ns;
  368. ulong newtop, newsize;
  369. int i, mapsize;
  370. Pte **map;
  371. s = up->seg[seg];
  372. if(s == 0)
  373. error(Ebadarg);
  374. if(addr == 0)
  375. return s->base;
  376. qlock(&s->lk);
  377. /* We may start with the bss overlapping the data */
  378. if(addr < s->base) {
  379. if(seg != BSEG || up->seg[DSEG] == 0 || addr < up->seg[DSEG]->base) {
  380. qunlock(&s->lk);
  381. error(Enovmem);
  382. }
  383. addr = s->base;
  384. }
  385. newtop = PGROUND(addr);
  386. newsize = (newtop-s->base)/BY2PG;
  387. if(newtop < s->top) {
  388. mfreeseg(s, newtop, (s->top-newtop)/BY2PG);
  389. s->top = newtop;
  390. s->size = newsize;
  391. qunlock(&s->lk);
  392. flushmmu();
  393. return 0;
  394. }
  395. if(swapfull()){
  396. qunlock(&s->lk);
  397. error(Enoswap);
  398. }
  399. for(i = 0; i < NSEG; i++) {
  400. ns = up->seg[i];
  401. if(ns == 0 || ns == s)
  402. continue;
  403. if(newtop >= ns->base && newtop < ns->top) {
  404. qunlock(&s->lk);
  405. error(Esoverlap);
  406. }
  407. }
  408. if(newsize > (SEGMAPSIZE*PTEPERTAB)) {
  409. qunlock(&s->lk);
  410. error(Enovmem);
  411. }
  412. mapsize = ROUND(newsize, PTEPERTAB)/PTEPERTAB;
  413. if(mapsize > s->mapsize){
  414. map = smalloc(mapsize*sizeof(Pte*));
  415. memmove(map, s->map, s->mapsize*sizeof(Pte*));
  416. if(s->map != s->ssegmap)
  417. free(s->map);
  418. s->map = map;
  419. s->mapsize = mapsize;
  420. }
  421. s->top = newtop;
  422. s->size = newsize;
  423. qunlock(&s->lk);
  424. return 0;
  425. }
  426. /*
  427. * called with s->lk locked
  428. */
  429. void
  430. mfreeseg(Segment *s, ulong start, int pages)
  431. {
  432. int i, j, size;
  433. ulong soff;
  434. Page *pg;
  435. Page *list;
  436. soff = start-s->base;
  437. j = (soff&(PTEMAPMEM-1))/BY2PG;
  438. size = s->mapsize;
  439. list = nil;
  440. for(i = soff/PTEMAPMEM; i < size; i++) {
  441. if(pages <= 0)
  442. break;
  443. if(s->map[i] == 0) {
  444. pages -= PTEPERTAB-j;
  445. j = 0;
  446. continue;
  447. }
  448. while(j < PTEPERTAB) {
  449. pg = s->map[i]->pages[j];
  450. /*
  451. * We want to zero s->map[i]->page[j] and putpage(pg),
  452. * but we have to make sure other processors flush the
  453. * entry from their TLBs before the page is freed.
  454. * We construct a list of the pages to be freed, zero
  455. * the entries, then (below) call procflushseg, and call
  456. * putpage on the whole list.
  457. *
  458. * Swapped-out pages don't appear in TLBs, so it's okay
  459. * to putswap those pages before procflushseg.
  460. */
  461. if(pg){
  462. if(onswap(pg))
  463. putswap(pg);
  464. else{
  465. pg->next = list;
  466. list = pg;
  467. }
  468. s->map[i]->pages[j] = 0;
  469. }
  470. if(--pages == 0)
  471. goto out;
  472. j++;
  473. }
  474. j = 0;
  475. }
  476. out:
  477. /* flush this seg in all other processes */
  478. if(s->ref > 1)
  479. procflushseg(s);
  480. /* free the pages */
  481. for(pg = list; pg != nil; pg = list){
  482. list = list->next;
  483. putpage(pg);
  484. }
  485. }
  486. Segment*
  487. isoverlap(Proc *p, ulong va, int len)
  488. {
  489. int i;
  490. Segment *ns;
  491. ulong newtop;
  492. newtop = va+len;
  493. for(i = 0; i < NSEG; i++) {
  494. ns = p->seg[i];
  495. if(ns == 0)
  496. continue;
  497. if((newtop > ns->base && newtop <= ns->top) ||
  498. (va >= ns->base && va < ns->top))
  499. return ns;
  500. }
  501. return nil;
  502. }
  503. int
  504. addphysseg(Physseg* new)
  505. {
  506. Physseg *ps;
  507. /*
  508. * Check not already entered and there is room
  509. * for a new entry and the terminating null entry.
  510. */
  511. lock(&physseglock);
  512. for(ps = physseg; ps->name; ps++){
  513. if(strcmp(ps->name, new->name) == 0){
  514. unlock(&physseglock);
  515. return -1;
  516. }
  517. }
  518. if(ps-physseg >= nelem(physseg)-2){
  519. unlock(&physseglock);
  520. return -1;
  521. }
  522. *ps = *new;
  523. unlock(&physseglock);
  524. return 0;
  525. }
  526. int
  527. isphysseg(char *name)
  528. {
  529. Physseg *ps;
  530. int rv = 0;
  531. lock(&physseglock);
  532. for(ps = physseg; ps->name; ps++){
  533. if(strcmp(ps->name, name) == 0){
  534. rv = 1;
  535. break;
  536. }
  537. }
  538. unlock(&physseglock);
  539. return rv;
  540. }
  541. ulong
  542. segattach(Proc *p, ulong attr, char *name, ulong va, ulong len)
  543. {
  544. int sno;
  545. Segment *s, *os;
  546. Physseg *ps;
  547. if(va != 0 && va >= USTKTOP)
  548. error(Ebadarg);
  549. validaddr((ulong)name, 1, 0);
  550. vmemchr(name, 0, ~0);
  551. for(sno = 0; sno < NSEG; sno++)
  552. if(p->seg[sno] == nil && sno != ESEG)
  553. break;
  554. if(sno == NSEG)
  555. error(Enovmem);
  556. /*
  557. * first look for a global segment with the
  558. * same name
  559. */
  560. if(_globalsegattach != nil){
  561. s = (*_globalsegattach)(p, name);
  562. if(s != nil){
  563. p->seg[sno] = s;
  564. return s->base;
  565. }
  566. }
  567. len = PGROUND(len);
  568. if(len == 0)
  569. error(Ebadarg);
  570. /*
  571. * Find a hole in the address space.
  572. * Starting at the lowest possible stack address - len,
  573. * check for an overlapping segment, and repeat at the
  574. * base of that segment - len until either a hole is found
  575. * or the address space is exhausted.
  576. */
  577. if(va == 0) {
  578. va = p->seg[SSEG]->base - len;
  579. for(;;) {
  580. os = isoverlap(p, va, len);
  581. if(os == nil)
  582. break;
  583. va = os->base;
  584. if(len > va)
  585. error(Enovmem);
  586. va -= len;
  587. }
  588. }
  589. va = va&~(BY2PG-1);
  590. if(isoverlap(p, va, len) != nil)
  591. error(Esoverlap);
  592. for(ps = physseg; ps->name; ps++)
  593. if(strcmp(name, ps->name) == 0)
  594. goto found;
  595. error(Ebadarg);
  596. found:
  597. if(len > ps->size)
  598. error(Enovmem);
  599. attr &= ~SG_TYPE; /* Turn off what is not allowed */
  600. attr |= ps->attr; /* Copy in defaults */
  601. s = newseg(attr, va, len/BY2PG);
  602. s->pseg = ps;
  603. p->seg[sno] = s;
  604. return va;
  605. }
  606. void
  607. pteflush(Pte *pte, int s, int e)
  608. {
  609. int i;
  610. Page *p;
  611. for(i = s; i < e; i++) {
  612. p = pte->pages[i];
  613. if(pagedout(p) == 0)
  614. memset(p->cachectl, PG_TXTFLUSH, sizeof(p->cachectl));
  615. }
  616. }
  617. long
  618. syssegflush(ulong *arg)
  619. {
  620. Segment *s;
  621. ulong addr, l;
  622. Pte *pte;
  623. int chunk, ps, pe, len;
  624. addr = arg[0];
  625. len = arg[1];
  626. while(len > 0) {
  627. s = seg(up, addr, 1);
  628. if(s == 0)
  629. error(Ebadarg);
  630. s->flushme = 1;
  631. more:
  632. l = len;
  633. if(addr+l > s->top)
  634. l = s->top - addr;
  635. ps = addr-s->base;
  636. pte = s->map[ps/PTEMAPMEM];
  637. ps &= PTEMAPMEM-1;
  638. pe = PTEMAPMEM;
  639. if(pe-ps > l){
  640. pe = ps + l;
  641. pe = (pe+BY2PG-1)&~(BY2PG-1);
  642. }
  643. if(pe == ps) {
  644. qunlock(&s->lk);
  645. error(Ebadarg);
  646. }
  647. if(pte)
  648. pteflush(pte, ps/BY2PG, pe/BY2PG);
  649. chunk = pe-ps;
  650. len -= chunk;
  651. addr += chunk;
  652. if(len > 0 && addr < s->top)
  653. goto more;
  654. qunlock(&s->lk);
  655. }
  656. flushmmu();
  657. return 0;
  658. }
  659. void
  660. segclock(ulong pc)
  661. {
  662. Segment *s;
  663. s = up->seg[TSEG];
  664. if(s == 0 || s->profile == 0)
  665. return;
  666. s->profile[0] += TK2MS(1);
  667. if(pc >= s->base && pc < s->top) {
  668. pc -= s->base;
  669. s->profile[pc>>LRESPROF] += TK2MS(1);
  670. }
  671. }