sysseg.c 9.0 KB

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