segment.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "u.h"
  10. #include "../port/lib.h"
  11. #include "mem.h"
  12. #include "dat.h"
  13. #include "fns.h"
  14. #include "../port/error.h"
  15. uintmem
  16. segppn(Segment *s, uintmem pa)
  17. {
  18. uintmem pgsz;
  19. pgsz = m->pgsz[s->pgszi];
  20. pa &= ~(pgsz-1);
  21. return pa;
  22. }
  23. /*
  24. * Sizes are given in multiples of BIGPGSZ.
  25. * The actual page size used is either BIGPGSZ or 1*GiB
  26. * if base is aligned to 1G and size is >= 1G and we support 1G pages.
  27. */
  28. Segment *
  29. newseg(int type, uintptr base, uint64_t size)
  30. {
  31. Segment *s;
  32. int mapsize;
  33. uint pgsz;
  34. if(size > SEGMAPSIZE*(PTEMAPMEM/BIGPGSZ))
  35. error(Enovmem);
  36. pgsz = BIGPGSZ;
  37. if(size*BIGPGSZ >= 1*GiB && getpgszi(1*GiB) >= 0 &&
  38. (base&(1ULL*GiB-1)) == 0 && ((size*BIGPGSZ)&(1ULL*GiB-1)) == 0){
  39. DBG("newseg: using 1G pages\n");
  40. pgsz = 1*GiB;
  41. }
  42. s = smalloc(sizeof(Segment));
  43. s->ref = 1;
  44. s->type = type;
  45. s->base = base;
  46. s->ptepertab = PTEMAPMEM/pgsz;
  47. s->top = base+(size*BIGPGSZ);
  48. s->size = size;
  49. s->pgszi = getpgszi(pgsz);
  50. if(s->pgszi < 0)
  51. panic("newseg: getpgszi %d", pgsz);
  52. s->sema.prev = &s->sema;
  53. s->sema.next = &s->sema;
  54. s->color = NOCOLOR;
  55. mapsize = HOWMANY(size*BIGPGSZ/pgsz, s->ptepertab);
  56. if(mapsize > nelem(s->ssegmap)){
  57. mapsize *= 2;
  58. if(mapsize > (SEGMAPSIZE*s->ptepertab))
  59. mapsize = (SEGMAPSIZE*s->ptepertab);
  60. s->map = smalloc(mapsize*sizeof(Pte*));
  61. s->mapsize = mapsize;
  62. }
  63. else{
  64. s->map = s->ssegmap;
  65. s->mapsize = nelem(s->ssegmap);
  66. }
  67. return s;
  68. }
  69. #define NHASH 101
  70. #define SHASH(np) (PTR2UINT(np)%NHASH)
  71. Sem*
  72. segmksem(Segment *sg, int *np)
  73. {
  74. Sem *s, **l;
  75. qlock(&sg->lk);
  76. if(sg->sems.s == nil)
  77. sg->sems.s = mallocz(NHASH * sizeof(Sem*), 1);
  78. for(l = &sg->sems.s[SHASH(np)]; (s = *l) != nil; l = &s->next)
  79. if(s->np == np){
  80. qunlock(&sg->lk);
  81. return s;
  82. }
  83. s = mallocz(sizeof *s, 1);
  84. s->np = np;
  85. *l = s;
  86. qunlock(&sg->lk);
  87. return s;
  88. }
  89. void
  90. putseg(Segment *s)
  91. {
  92. Pte **pp, **emap;
  93. Image *i;
  94. extern void freezseg(Segment*);
  95. if(s == 0)
  96. return;
  97. i = s->image;
  98. if(i != 0) {
  99. lock(i);
  100. lock(s);
  101. if(i->s == s && s->ref == 1)
  102. i->s = 0;
  103. unlock(i);
  104. }
  105. else
  106. lock(s);
  107. s->ref--;
  108. if(s->ref != 0) {
  109. unlock(s);
  110. return;
  111. }
  112. unlock(s);
  113. qlock(&s->lk);
  114. if(i)
  115. putimage(i);
  116. emap = &s->map[s->mapsize];
  117. for(pp = s->map; pp < emap; pp++)
  118. if(*pp)
  119. freepte(s, *pp);
  120. qunlock(&s->lk);
  121. if(s->map != s->ssegmap)
  122. free(s->map);
  123. if(s->profile != 0)
  124. free(s->profile);
  125. if(s->sems.s != nil)
  126. free(s->sems.s);
  127. if(s->type&SG_ZIO)
  128. freezseg(s);
  129. free(s);
  130. }
  131. void
  132. relocateseg(Segment *s, uintptr offset)
  133. {
  134. Page **pg, *x;
  135. Pte *pte, **p, **endpte;
  136. endpte = &s->map[s->mapsize];
  137. for(p = s->map; p < endpte; p++) {
  138. if(*p == 0)
  139. continue;
  140. pte = *p;
  141. for(pg = pte->first; pg <= pte->last; pg++) {
  142. if(x = *pg)
  143. x->va += offset;
  144. }
  145. }
  146. }
  147. Segment*
  148. dupseg(Segment **seg, int segno, int share)
  149. {
  150. int i, size;
  151. Pte *pte;
  152. Segment *n, *s;
  153. SET(n);
  154. s = seg[segno];
  155. qlock(&s->lk);
  156. if(waserror()){
  157. qunlock(&s->lk);
  158. nexterror();
  159. }
  160. switch(s->type&SG_TYPE) {
  161. case SG_TEXT: /* New segment shares pte set */
  162. case SG_SHARED:
  163. case SG_PHYSICAL:
  164. goto sameseg;
  165. case SG_STACK:
  166. n = newseg(s->type, s->base, s->size);
  167. break;
  168. case SG_BSS: /* Just copy on write */
  169. if(share)
  170. goto sameseg;
  171. n = newseg(s->type, s->base, s->size);
  172. break;
  173. case SG_DATA: /* Copy on write plus demand load info */
  174. if(segno == TSEG){
  175. poperror();
  176. qunlock(&s->lk);
  177. return data2txt(s);
  178. }
  179. if(share)
  180. goto sameseg;
  181. n = newseg(s->type, s->base, s->size);
  182. incref(s->image);
  183. n->image = s->image;
  184. n->fstart = s->fstart;
  185. n->flen = s->flen;
  186. n->pgszi = s->pgszi;
  187. n->color = s->color;
  188. n->ptepertab = s->ptepertab;
  189. break;
  190. }
  191. size = s->mapsize;
  192. for(i = 0; i < size; i++)
  193. if(pte = s->map[i])
  194. n->map[i] = ptecpy(n, pte);
  195. n->flushme = s->flushme;
  196. if(s->ref > 1)
  197. procflushseg(s);
  198. poperror();
  199. qunlock(&s->lk);
  200. return n;
  201. sameseg:
  202. incref(s);
  203. poperror();
  204. qunlock(&s->lk);
  205. return s;
  206. }
  207. void
  208. segpage(Segment *s, Page *p)
  209. {
  210. Pte **pte;
  211. uintptr soff;
  212. uintmem pgsz;
  213. Page **pg;
  214. if(s->pgszi < 0)
  215. s->pgszi = p->pgszi;
  216. if(s->color == NOCOLOR)
  217. s->color = p->color;
  218. if(s->pgszi != p->pgszi)
  219. panic("segpage: s->pgszi != p->pgszi");
  220. if(p->va < s->base || p->va >= s->top)
  221. panic("segpage: p->va < s->base || p->va >= s->top");
  222. soff = p->va - s->base;
  223. pte = &s->map[soff/PTEMAPMEM];
  224. if(*pte == 0)
  225. *pte = ptealloc(s);
  226. pgsz = m->pgsz[s->pgszi];
  227. pg = &(*pte)->pages[(soff&(PTEMAPMEM-1))/pgsz];
  228. *pg = p;
  229. if(pg < (*pte)->first)
  230. (*pte)->first = pg;
  231. if(pg > (*pte)->last)
  232. (*pte)->last = pg;
  233. }
  234. /*
  235. * called with s->lk locked
  236. */
  237. void
  238. mfreeseg(Segment *s, uintptr start, int pages)
  239. {
  240. int i, j, size;
  241. uintptr soff;
  242. uintmem pgsz;
  243. Page *pg;
  244. Page *list;
  245. pgsz = m->pgsz[s->pgszi];
  246. soff = start-s->base;
  247. j = (soff&(PTEMAPMEM-1))/pgsz;
  248. size = s->mapsize;
  249. list = nil;
  250. for(i = soff/PTEMAPMEM; i < size; i++) {
  251. if(pages <= 0)
  252. break;
  253. if(s->map[i] == 0) {
  254. pages -= s->ptepertab-j;
  255. j = 0;
  256. continue;
  257. }
  258. while(j < s->ptepertab) {
  259. pg = s->map[i]->pages[j];
  260. /*
  261. * We want to zero s->map[i]->page[j] and putpage(pg),
  262. * but we have to make sure other processors flush the
  263. * entry from their TLBs before the page is freed.
  264. * We construct a list of the pages to be freed, zero
  265. * the entries, then (below) call procflushseg, and call
  266. * putpage on the whole list.
  267. *
  268. * Swapped-out pages don't appear in TLBs, so it's okay
  269. * to putswap those pages before procflushseg.
  270. */
  271. if(pg){
  272. if(onswap(pg))
  273. putswap(pg);
  274. else{
  275. pg->next = list;
  276. list = pg;
  277. }
  278. s->map[i]->pages[j] = 0;
  279. }
  280. if(--pages == 0)
  281. goto out;
  282. j++;
  283. }
  284. j = 0;
  285. }
  286. out:
  287. /* flush this seg in all other processes */
  288. if(s->ref > 1)
  289. procflushseg(s);
  290. /* free the pages */
  291. for(pg = list; pg != nil; pg = list){
  292. list = list->next;
  293. putpage(pg);
  294. }
  295. }
  296. Segment*
  297. isoverlap(Proc* p, uintptr va, usize len)
  298. {
  299. int i;
  300. Segment *ns;
  301. uintptr newtop;
  302. newtop = va+len;
  303. for(i = 0; i < NSEG; i++) {
  304. ns = p->seg[i];
  305. if(ns == 0)
  306. continue;
  307. if((newtop > ns->base && newtop <= ns->top) ||
  308. (va >= ns->base && va < ns->top))
  309. return ns;
  310. }
  311. return nil;
  312. }
  313. void
  314. segclock(uintptr pc)
  315. {
  316. Segment *s;
  317. s = up->seg[TSEG];
  318. if(s == 0 || s->profile == 0)
  319. return;
  320. s->profile[0] += TK2MS(1);
  321. if(pc >= s->base && pc < s->top) {
  322. pc -= s->base;
  323. s->profile[pc>>LRESPROF] += TK2MS(1);
  324. }
  325. }
  326. static void
  327. prepageseg(int i)
  328. {
  329. Segment *s;
  330. uintptr addr, pgsz;
  331. s = up->seg[i];
  332. if(s == nil)
  333. return;
  334. DBG("prepage: base %#p top %#p\n", s->base, s->top);
  335. pgsz = m->pgsz[s->pgszi];
  336. for(addr = s->base; addr < s->top; addr += pgsz)
  337. fault(addr, i == TSEG);
  338. }
  339. /*
  340. * BUG: should depend only in segment attributes, not in
  341. * the slot used in up->seg.
  342. */
  343. void
  344. nixprepage(int i)
  345. {
  346. if(i >= 0)
  347. prepageseg(i);
  348. else
  349. for(i = 0; i < NSEG; i++)
  350. prepageseg(i);
  351. }