sysseg.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  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. Segment* (*_globalsegattach)(Proc*, char*);
  16. static Lock physseglock;
  17. int
  18. addphysseg(Physseg* new)
  19. {
  20. Physseg *ps;
  21. /*
  22. * Check not already entered and there is room
  23. * for a new entry and the terminating null entry.
  24. */
  25. lock(&physseglock);
  26. for(ps = physseg; ps->name; ps++){
  27. if(strcmp(ps->name, new->name) == 0){
  28. unlock(&physseglock);
  29. return -1;
  30. }
  31. }
  32. if(ps-physseg >= nphysseg-2){
  33. unlock(&physseglock);
  34. return -1;
  35. }
  36. if(new->pgszi < 0)
  37. new->pgszi = getpgszi(2*MiB); /* 2M pages by default */
  38. if(new->pgszi < 0)
  39. panic("addphysseg");
  40. *ps = *new;
  41. unlock(&physseglock);
  42. return 0;
  43. }
  44. int
  45. isphysseg(char *name)
  46. {
  47. int rv;
  48. Physseg *ps;
  49. lock(&physseglock);
  50. rv = 0;
  51. for(ps = physseg; ps->name; ps++){
  52. if(strcmp(ps->name, name) == 0){
  53. rv = 1;
  54. break;
  55. }
  56. }
  57. unlock(&physseglock);
  58. return rv;
  59. }
  60. /* Needs to be non-static for BGP support */
  61. uintptr_t
  62. ibrk(uintptr_t addr, int seg)
  63. {
  64. Mach *m = machp();
  65. Segment *s, *ns;
  66. uintptr_t newtop, rtop;
  67. int32_t newsize;
  68. int i, mapsize;
  69. Pte **map;
  70. uintmem pgsz;
  71. s = m->externup->seg[seg];
  72. if(s == 0)
  73. error(Ebadarg);
  74. if(addr == 0)
  75. return s->top;
  76. qlock(&s->lk);
  77. if(waserror()) {
  78. qunlock(&s->lk);
  79. nexterror();
  80. }
  81. /* We may start with the bss overlapping the data */
  82. if(addr < s->base) {
  83. if(seg != BSEG || m->externup->seg[DSEG] == 0 || addr < m->externup->seg[DSEG]->base)
  84. error(Enovmem);
  85. addr = s->base;
  86. }
  87. pgsz = m->pgsz[s->pgszi];
  88. if(seg == BSEG && addr >= ROUNDUP(s->top, 1*GiB) + 1*GiB)
  89. newtop = ROUNDUP(addr, 1*GiB);
  90. else
  91. newtop = ROUNDUP(addr, pgsz);
  92. newsize = (newtop-s->base)/pgsz;
  93. if(newtop < s->top) {
  94. mfreeseg(s, newtop, (s->top-newtop)/pgsz);
  95. s->top = newtop;
  96. s->size = newsize;
  97. poperror();
  98. qunlock(&s->lk);
  99. mmuflush();
  100. return newtop;
  101. }
  102. if(newsize > (SEGMAPSIZE*s->ptepertab))
  103. error(Enovmem);
  104. for(i = 0; i < NSEG; i++) {
  105. ns = m->externup->seg[i];
  106. if(ns == 0 || ns == s)
  107. continue;
  108. if(newtop >= ns->base && newtop < ns->top)
  109. error(Esoverlap);
  110. }
  111. if(seg == BSEG && newtop >= ROUNDUP(s->top, 1*GiB) + 1*GiB){
  112. DBG("segment using 1G pages\n");
  113. /*
  114. * brk the bss up to the 1G boundary, and create
  115. * a segment placed at that boundary, using 1G pages if it can.
  116. * This is both back compatible, transparent,
  117. * and permits using 1G pages.
  118. */
  119. rtop = ROUNDUP(newtop,1*GiB);
  120. newtop = ROUNDUP(s->top, 1*GiB);
  121. newsize -= (rtop-newtop)/BIGPGSZ;
  122. assert(newsize >= 0);
  123. DBG("ibrk: newseg %#ullx %ullx\n", newtop, (rtop-newtop)/BIGPGSZ);
  124. ns = newseg(SG_BSS, newtop, (rtop-newtop)/BIGPGSZ);
  125. ns->color= s->color;
  126. m->externup->seg[HSEG] = ns;
  127. DBG("ibrk: newtop %#ullx newsize %#ulx \n", newtop, newsize);
  128. /* now extend the bss up to newtop */
  129. }else
  130. rtop = newtop;
  131. mapsize = HOWMANY(newsize, s->ptepertab);
  132. if(mapsize > s->mapsize){
  133. map = smalloc(mapsize*sizeof(Pte*));
  134. memmove(map, s->map, s->mapsize*sizeof(Pte*));
  135. if(s->map != s->ssegmap)
  136. free(s->map);
  137. s->map = map;
  138. s->mapsize = mapsize;
  139. }
  140. s->top = newtop;
  141. s->size = newsize;
  142. poperror();
  143. qunlock(&s->lk);
  144. return rtop;
  145. }
  146. void
  147. syssegbrk(Ar0* ar0, ...)
  148. {
  149. Mach *m = machp();
  150. int i;
  151. uintptr_t addr;
  152. Segment *s;
  153. va_list list;
  154. va_start(list, ar0);
  155. /*
  156. * int segbrk(void*, void*);
  157. * should be
  158. * void* segbrk(void* saddr, void* addr);
  159. */
  160. addr = PTR2UINT(va_arg(list, void*));
  161. if(addr == 0){
  162. if(m->externup->seg[HSEG])
  163. ar0->v = UINT2PTR(m->externup->seg[HSEG]->top);
  164. else
  165. ar0->v = UINT2PTR(m->externup->seg[BSEG]->top);
  166. return;
  167. }
  168. for(i = 0; i < NSEG; i++) {
  169. s = m->externup->seg[i];
  170. if(s == nil)
  171. continue;
  172. /* Ok to extend an empty segment */
  173. if(addr < s->base || addr > s->top)
  174. continue;
  175. if(addr == s->top && (s->base < s->top))
  176. continue;
  177. switch(s->type&SG_TYPE) {
  178. case SG_TEXT:
  179. case SG_DATA:
  180. case SG_STACK:
  181. error(Ebadarg);
  182. default:
  183. addr = PTR2UINT(va_arg(list, void*));
  184. ar0->v = UINT2PTR(ibrk(addr, i));
  185. return;
  186. }
  187. }
  188. va_end(list);
  189. error(Ebadarg);
  190. }
  191. void
  192. sysbrk_(Ar0* ar0, ...)
  193. {
  194. uintptr_t addr;
  195. va_list list;
  196. va_start(list, ar0);
  197. /*
  198. * int brk(void*);
  199. *
  200. * Deprecated; should be for backwards compatibility only.
  201. */
  202. addr = PTR2UINT(va_arg(list, void*));
  203. va_end(list);
  204. ibrk(addr, BSEG);
  205. ar0->i = 0;
  206. }
  207. static uintptr_t
  208. segattach(Proc* p, int attr, char* name, uintptr_t va, usize len)
  209. {
  210. Mach *m = machp();
  211. int sno;
  212. Segment *s, *os;
  213. Physseg *ps;
  214. /* BUG: Only ok for now */
  215. if((va != 0 && va < UTZERO) || (va & KZERO) == KZERO)
  216. error("virtual address in kernel");
  217. vmemchr(name, 0, ~0);
  218. for(sno = 0; sno < NSEG; sno++)
  219. if(p->seg[sno] == nil && sno != ESEG)
  220. break;
  221. if(sno == NSEG)
  222. error("too many segments in process");
  223. /*
  224. * first look for a global segment with the
  225. * same name
  226. */
  227. if(_globalsegattach != nil){
  228. s = (*_globalsegattach)(p, name);
  229. if(s != nil){
  230. p->seg[sno] = s;
  231. if(p == m->externup && m->externup->prepagemem)
  232. nixprepage(sno);
  233. return s->base;
  234. }
  235. }
  236. for(ps = physseg; ps->name != nil; ps++)
  237. if(strcmp(name, ps->name) == 0)
  238. break;
  239. if(ps->name == nil)
  240. error("segment not found");
  241. if(va == 0 && ps->gva != 0){
  242. va = ps->gva;
  243. if(len == 0)
  244. len = ps->size*BIGPGSZ;
  245. }
  246. if(len == 0)
  247. error("zero length");
  248. len = BIGPGROUND(len);
  249. if(len == 0)
  250. error("length overflow");
  251. /*
  252. * Find a hole in the address space.
  253. * Starting at the lowest possible stack address - len,
  254. * check for an overlapping segment, and repeat at the
  255. * base of that segment - len until either a hole is found
  256. * or the address space is exhausted.
  257. */
  258. if(va == 0) {
  259. va = p->seg[SSEG]->base - len;
  260. for(;;) {
  261. os = isoverlap(p, va, len);
  262. if(os == nil)
  263. break;
  264. va = os->base;
  265. if(len > va)
  266. error("cannot fit segment at virtual address");
  267. va -= len;
  268. }
  269. }
  270. va = va&~(BIGPGSZ-1);
  271. if(isoverlap(p, va, len) != nil)
  272. error(Esoverlap);
  273. if((len/BIGPGSZ) > ps->size)
  274. error("len > segment size");
  275. attr &= ~SG_TYPE; /* Turn off what is not allowed */
  276. attr |= ps->attr; /* Copy in defaults */
  277. s = newseg(attr, va, len/BIGPGSZ);
  278. s->pseg = ps;
  279. p->seg[sno] = s;
  280. if(p == m->externup && m->externup->prepagemem)
  281. nixprepage(sno);
  282. return va;
  283. }
  284. void
  285. syssegattach(Ar0* ar0, ...)
  286. {
  287. Mach *m = machp();
  288. int attr;
  289. char *name;
  290. uintptr_t va;
  291. usize len;
  292. va_list list;
  293. va_start(list, ar0);
  294. /*
  295. * long segattach(int, char*, void*, uint32_t);
  296. * should be
  297. * void* segattach(int, char*, void*, usize);
  298. */
  299. attr = va_arg(list, int);
  300. name = va_arg(list, char*);
  301. va = PTR2UINT(va_arg(list, void*));
  302. len = va_arg(list, usize);
  303. va_end(list);
  304. ar0->v = UINT2PTR(segattach(m->externup, attr, validaddr(name, 1, 0), va, len));
  305. }
  306. void
  307. syssegdetach(Ar0* ar0, ...)
  308. {
  309. Mach *m = machp();
  310. int i;
  311. uintptr_t addr;
  312. Segment *s;
  313. va_list list;
  314. va_start(list, ar0);
  315. /*
  316. * int segdetach(void*);
  317. */
  318. addr = PTR2UINT(va_arg(list, void*));
  319. va_end(list);
  320. qlock(&m->externup->seglock);
  321. if(waserror()){
  322. qunlock(&m->externup->seglock);
  323. nexterror();
  324. }
  325. s = 0;
  326. for(i = 0; i < NSEG; i++)
  327. if(s = m->externup->seg[i]) {
  328. qlock(&s->lk);
  329. if((addr >= s->base && addr < s->top) ||
  330. (s->top == s->base && addr == s->base))
  331. goto found;
  332. qunlock(&s->lk);
  333. }
  334. error(Ebadarg);
  335. found:
  336. /*
  337. * Can't detach the initial stack segment
  338. * because the clock writes profiling info
  339. * there.
  340. */
  341. if(s == m->externup->seg[SSEG]){
  342. qunlock(&s->lk);
  343. error(Ebadarg);
  344. }
  345. m->externup->seg[i] = 0;
  346. qunlock(&s->lk);
  347. putseg(s);
  348. qunlock(&m->externup->seglock);
  349. poperror();
  350. /* Ensure we flush any entries from the lost segment */
  351. mmuflush();
  352. ar0->i = 0;
  353. }
  354. void
  355. syssegfree(Ar0* ar0, ...)
  356. {
  357. Mach *m = machp();
  358. Segment *s;
  359. uintptr_t from, to;
  360. usize len;
  361. va_list list;
  362. va_start(list, ar0);
  363. /*
  364. * int segfree(void*, uint32_t);
  365. * should be
  366. * int segfree(void*, usize);
  367. */
  368. from = PTR2UINT(va_arg(list, void*));
  369. s = seg(m->externup, from, 1);
  370. if(s == nil)
  371. error(Ebadarg);
  372. len = va_arg(list, usize);
  373. to = (from + len) & ~(BIGPGSZ-1);
  374. if(to < from || to > s->top){
  375. qunlock(&s->lk);
  376. error(Ebadarg);
  377. }
  378. from = BIGPGROUND(from);
  379. va_end(list);
  380. mfreeseg(s, from, (to - from) / BIGPGSZ);
  381. qunlock(&s->lk);
  382. mmuflush();
  383. ar0->i = 0;
  384. }
  385. static void
  386. pteflush(Pte *pte, int s, int e)
  387. {
  388. int i;
  389. Page *p;
  390. for(i = s; i < e; i++) {
  391. p = pte->pages[i];
  392. if(pagedout(p) == 0)
  393. memset(p->cachectl, PG_TXTFLUSH, sizeof(p->cachectl));
  394. }
  395. }
  396. void
  397. syssegflush(Ar0* ar0, ...)
  398. {
  399. Mach *m = machp();
  400. Segment *s;
  401. uintptr_t addr;
  402. Pte *pte;
  403. usize chunk, l, len, pe, ps;
  404. va_list list;
  405. va_start(list, ar0);
  406. /*
  407. * int segflush(void*, uint32_t);
  408. * should be
  409. * int segflush(void*, usize);
  410. */
  411. addr = PTR2UINT(va_arg(list, void*));
  412. len = va_arg(list, usize);
  413. va_end(list);
  414. while(len > 0) {
  415. s = seg(m->externup, addr, 1);
  416. if(s == nil)
  417. error(Ebadarg);
  418. s->flushme = 1;
  419. more:
  420. l = len;
  421. if(addr+l > s->top)
  422. l = s->top - addr;
  423. ps = addr-s->base;
  424. pte = s->map[ps/PTEMAPMEM];
  425. ps &= PTEMAPMEM-1;
  426. pe = PTEMAPMEM;
  427. if(pe-ps > l){
  428. pe = ps + l;
  429. pe = (pe+BIGPGSZ-1)&~(BIGPGSZ-1);
  430. }
  431. if(pe == ps) {
  432. qunlock(&s->lk);
  433. error(Ebadarg);
  434. }
  435. if(pte)
  436. pteflush(pte, ps/BIGPGSZ, pe/BIGPGSZ);
  437. chunk = pe-ps;
  438. len -= chunk;
  439. addr += chunk;
  440. if(len > 0 && addr < s->top)
  441. goto more;
  442. qunlock(&s->lk);
  443. }
  444. mmuflush();
  445. ar0->i = 0;
  446. }