devsegment.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784
  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. enum
  16. {
  17. Qtopdir,
  18. Qsegdir,
  19. Qctl,
  20. Qdata,
  21. Qfree,
  22. /* commands to kproc */
  23. Cnone=0,
  24. Cread,
  25. Cwrite,
  26. Cstart,
  27. Cdie,
  28. };
  29. #define TYPE(x) (int)( (c)->qid.path & 0x7 )
  30. #define SEG(x) ( ((c)->qid.path >> 3) & 0x3f )
  31. #define PATH(s, t) ( ((s)<<3) | (t) )
  32. typedef struct Globalseg Globalseg;
  33. typedef struct Freemsg Freemsg;
  34. struct Freemsg
  35. {
  36. Freemsg *next;
  37. };
  38. struct Globalseg
  39. {
  40. Ref r;
  41. Segment *s;
  42. char *name;
  43. char *uid;
  44. int64_t length;
  45. long perm;
  46. Freemsg *free;
  47. /* kproc to do reading and writing */
  48. QLock ql; /* sync kproc access */
  49. Rendez cmdwait; /* where kproc waits */
  50. Rendez replywait; /* where requestor waits */
  51. Proc *kproc;
  52. char *data;
  53. long off;
  54. int dlen;
  55. int cmd;
  56. char err[64];
  57. };
  58. static Globalseg *globalseg[100];
  59. static Lock globalseglock;
  60. Segment *heapseg;
  61. Segment* (*_globalsegattach)(Proc*, char*);
  62. static Segment* globalsegattach(Proc*, char*);
  63. static int cmddone(void*);
  64. static void segmentkproc(void*);
  65. static void docmd(Globalseg*, int);
  66. /*
  67. * returns with globalseg incref'd
  68. */
  69. static Globalseg*
  70. getgseg(Chan *c)
  71. {
  72. int x;
  73. Globalseg *g;
  74. x = SEG(c);
  75. lock(&globalseglock);
  76. if(x >= nelem(globalseg))
  77. panic("getgseg");
  78. g = globalseg[x];
  79. if(g != nil)
  80. incref(&g->r);
  81. unlock(&globalseglock);
  82. if(g == nil)
  83. error("global segment disappeared");
  84. return g;
  85. }
  86. static void
  87. putgseg(Globalseg *g)
  88. {
  89. if(decref(&g->r) > 0)
  90. return;
  91. if(g->s == heapseg)
  92. heapseg = nil;
  93. if(g->s != nil)
  94. putseg(g->s);
  95. if(g->kproc)
  96. docmd(g, Cdie);
  97. free(g->name);
  98. free(g->uid);
  99. free(g);
  100. }
  101. static int
  102. segmentgen(Chan *c, char* d, Dirtab* dir, int i, int s, Dir *dp)
  103. {
  104. Proc *up = externup();
  105. Qid q;
  106. Globalseg *g;
  107. uint32_t size;
  108. switch(TYPE(c)) {
  109. case Qtopdir:
  110. if(s == DEVDOTDOT){
  111. q.vers = 0;
  112. q.path = PATH(0, Qtopdir);
  113. q.type = QTDIR;
  114. devdir(c, q, "#g", 0, eve, DMDIR|0777, dp);
  115. break;
  116. }
  117. if(s >= nelem(globalseg))
  118. return -1;
  119. lock(&globalseglock);
  120. g = globalseg[s];
  121. if(g == nil){
  122. unlock(&globalseglock);
  123. return 0;
  124. }
  125. q.vers = 0;
  126. q.path = PATH(s, Qsegdir);
  127. q.type = QTDIR;
  128. devdir(c, q, g->name, 0, g->uid, DMDIR|0777, dp);
  129. unlock(&globalseglock);
  130. break;
  131. case Qsegdir:
  132. if(s == DEVDOTDOT){
  133. q.vers = 0;
  134. q.path = PATH(0, Qtopdir);
  135. q.type = QTDIR;
  136. devdir(c, q, "#g", 0, eve, DMDIR|0777, dp);
  137. break;
  138. }
  139. /* fall through */
  140. case Qctl:
  141. case Qdata:
  142. case Qfree:
  143. g = getgseg(c);
  144. if(waserror()){
  145. putgseg(g);
  146. nexterror();
  147. }
  148. q.vers = 0;
  149. q.type = QTFILE;
  150. switch(s){
  151. case 0:
  152. q.path = PATH(SEG(c), Qctl);
  153. devdir(c, q, "ctl", 0, g->uid, g->perm, dp);
  154. break;
  155. case 1:
  156. q.path = PATH(SEG(c), Qdata);
  157. if(g->s != nil)
  158. size = g->s->top - g->s->base;
  159. else
  160. size = 0;
  161. devdir(c, q, "data", size, g->uid, g->perm, dp);
  162. break;
  163. case 2:
  164. q.path = PATH(SEG(c), Qfree);
  165. devdir(c, q, "free", 0, g->uid, g->perm&0444, dp);
  166. break;
  167. default:
  168. poperror();
  169. putgseg(g);
  170. return -1;
  171. }
  172. poperror();
  173. putgseg(g);
  174. break;
  175. }
  176. return 1;
  177. }
  178. static void
  179. segmentinit(void)
  180. {
  181. _globalsegattach = globalsegattach;
  182. }
  183. static Chan*
  184. segmentattach(char *spec)
  185. {
  186. return devattach('g', spec);
  187. }
  188. static Walkqid*
  189. segmentwalk(Chan *c, Chan *nc, char **name, int nname)
  190. {
  191. return devwalk(c, nc, name, nname, 0, 0, segmentgen);
  192. }
  193. static int32_t
  194. segmentstat(Chan *c, uint8_t *db, int32_t n)
  195. {
  196. return devstat(c, db, n, 0, 0, segmentgen);
  197. }
  198. static int
  199. cmddone(void *arg)
  200. {
  201. Globalseg *g = arg;
  202. return g->cmd == Cnone;
  203. }
  204. static Chan*
  205. segmentopen(Chan *c, int omode)
  206. {
  207. Proc *up = externup();
  208. Globalseg *g;
  209. switch(TYPE(c)){
  210. case Qtopdir:
  211. case Qsegdir:
  212. if(omode != 0)
  213. error(Eisdir);
  214. break;
  215. case Qctl:
  216. case Qfree:
  217. g = getgseg(c);
  218. if(waserror()){
  219. putgseg(g);
  220. nexterror();
  221. }
  222. devpermcheck(g->uid, g->perm, omode);
  223. c->aux = g;
  224. poperror();
  225. c->flag |= COPEN;
  226. break;
  227. case Qdata:
  228. g = getgseg(c);
  229. if(waserror()){
  230. putgseg(g);
  231. nexterror();
  232. }
  233. devpermcheck(g->uid, g->perm, omode);
  234. if(g->s == nil)
  235. error("segment not yet allocated");
  236. if(g->kproc == nil){
  237. qlock(&g->ql);
  238. if(waserror()){
  239. qunlock(&g->ql);
  240. nexterror();
  241. }
  242. if(g->kproc == nil){
  243. g->cmd = Cnone;
  244. kproc(g->name, segmentkproc, g);
  245. docmd(g, Cstart);
  246. }
  247. poperror();
  248. qunlock(&g->ql);
  249. }
  250. c->aux = g;
  251. poperror();
  252. c->flag |= COPEN;
  253. break;
  254. default:
  255. panic("segmentopen");
  256. }
  257. c->mode = openmode(omode);
  258. c->offset = 0;
  259. return c;
  260. }
  261. static void
  262. segmentclose(Chan *c)
  263. {
  264. if(TYPE(c) == Qtopdir)
  265. return;
  266. if(c->flag & COPEN)
  267. putgseg(c->aux);
  268. }
  269. static void
  270. segmentcreate(Chan *c, char *name, int omode, int perm)
  271. {
  272. Proc *up = externup();
  273. int x, xfree;
  274. Globalseg *g;
  275. char *ep;
  276. if(TYPE(c) != Qtopdir)
  277. error(Eperm);
  278. if(isphysseg(name))
  279. error(Eexist);
  280. if((perm & DMDIR) == 0)
  281. error("must create directory");
  282. if(waserror()){
  283. unlock(&globalseglock);
  284. nexterror();
  285. }
  286. xfree = -1;
  287. if(name[0] == '#' && name[1] >= '0' && name[1] <= '9'){
  288. /* hack for cnk: if #n, treat it as index n */
  289. xfree = strtoul(name+1, &ep, 0);
  290. if(*ep)
  291. xfree = -1;
  292. else if(xfree < 0 || xfree >= nelem(globalseg))
  293. error("invalid global segment index");
  294. }
  295. lock(&globalseglock);
  296. if(xfree < 0){
  297. for(x = 0; x < nelem(globalseg); x++){
  298. g = globalseg[x];
  299. if(g == nil){
  300. if(xfree < 0)
  301. xfree = x;
  302. } else {
  303. if(strcmp(g->name, name) == 0)
  304. error(Eexist);
  305. }
  306. }
  307. if(xfree < 0)
  308. error("too many global segments");
  309. }else{
  310. g = globalseg[xfree];
  311. if(g != nil)
  312. error(Eexist);
  313. }
  314. g = smalloc(sizeof(Globalseg));
  315. g->r.ref = 1;
  316. kstrdup(&g->name, name);
  317. kstrdup(&g->uid, up->user);
  318. g->perm = 0660;
  319. globalseg[xfree] = g;
  320. unlock(&globalseglock);
  321. poperror();
  322. c->qid.path = PATH(xfree, Qsegdir);
  323. c->qid.type = QTDIR;
  324. c->qid.vers = 0;
  325. c->mode = openmode(omode);
  326. c->mode = OWRITE;
  327. DBG("segmentcreate(%s, %#o %#x)\n", name, omode, perm);
  328. }
  329. enum{PTRSIZE = 19}; /* "0x1234567812345678 " */
  330. static int
  331. readptr(char *buf, int32_t n, uintptr_t val)
  332. {
  333. if(n < PTRSIZE)
  334. return 0;
  335. snprint(buf, sizeof buf, "%*#llx", PTRSIZE-1, val);
  336. buf[PTRSIZE-1] = ' ';
  337. return PTRSIZE;
  338. }
  339. static int
  340. znotempty(void *x)
  341. {
  342. Zseg *zs;
  343. zs = x;
  344. return zs->end != 0;
  345. }
  346. static int32_t
  347. segmentread(Chan *c, void *a, int32_t n, int64_t voff)
  348. {
  349. Proc *up = externup();
  350. Globalseg *g;
  351. Zseg *zs;
  352. uintptr_t va;
  353. char *p, *s;
  354. int32_t tot;
  355. char buf[64];
  356. if(c->qid.type == QTDIR)
  357. return devdirread(c, a, n, (Dirtab *)0, 0L, segmentgen);
  358. g = c->aux;
  359. switch(TYPE(c)){
  360. case Qfree:
  361. if(g->s == nil)
  362. error("segment not yet allocated");
  363. if(n < PTRSIZE)
  364. error("read buffer too small");
  365. zs = &g->s->zseg;
  366. qlock(&g->s->lk);
  367. if(waserror()){
  368. qunlock(&g->s->lk);
  369. nexterror();
  370. }
  371. while((va = zgetaddr(g->s)) == 0ULL){
  372. qunlock(&g->s->lk);
  373. sleep(&zs->rr, znotempty, zs);
  374. qlock(&g->s->lk);
  375. }
  376. p = a;
  377. for(tot = 0; n-tot > PTRSIZE; tot += PTRSIZE){
  378. p += readptr(p, n, va);
  379. if((va = zgetaddr(g->s)) == 0ULL)
  380. break;
  381. }
  382. poperror();
  383. qunlock(&g->s->lk);
  384. return tot;
  385. case Qctl:
  386. if(g->s == nil)
  387. error("segment not yet allocated");
  388. if(g->s->type&SG_KZIO)
  389. s = "kmsg";
  390. else if(g->s->type&SG_ZIO)
  391. s = "umsg";
  392. else
  393. s = "addr";
  394. snprint(buf, sizeof(buf), "%s %#p %#p\n",
  395. s, g->s->base, (uintptr_t)(g->s->top-g->s->base));
  396. return readstr(voff, a, n, buf);
  397. case Qdata:
  398. if(voff < 0)
  399. error(Enegoff);
  400. if(voff + n > g->s->top - g->s->base){
  401. n = g->s->top - voff;
  402. if(n <= 0)
  403. break;
  404. }
  405. qlock(&g->ql);
  406. if(waserror()){
  407. qunlock(&g->ql);
  408. nexterror();
  409. }
  410. g->off = voff + g->s->base;
  411. g->data = smalloc(n);
  412. if(waserror()){
  413. free(g->data);
  414. nexterror();
  415. }
  416. g->dlen = n;
  417. docmd(g, Cread);
  418. memmove(a, g->data, g->dlen);
  419. poperror();
  420. free(g->data);
  421. poperror();
  422. qunlock(&g->ql);
  423. return g->dlen;
  424. default:
  425. panic("segmentread");
  426. }
  427. return 0; /* not reached */
  428. }
  429. /*
  430. * BUG: we allocate virtual addresses but never give them
  431. * back when the segment is destroyed.
  432. * BUG: what if we overlap other segments attached by the user?
  433. */
  434. static uintptr_t
  435. placeseg(uintptr_t len)
  436. {
  437. static Lock lck;
  438. static uintptr_t va = HEAPTOP;
  439. uintptr_t v;
  440. len += BIGPGSZ; /* so we fault upon overflows */
  441. lock(&lck);
  442. len = BIGPGROUND(len);
  443. va -= len;
  444. v = va;
  445. unlock(&lck);
  446. return v;
  447. }
  448. static int32_t
  449. segmentwrite(Chan *c, void *a, int32_t n, int64_t voff)
  450. {
  451. Proc *up = externup();
  452. Cmdbuf *cb;
  453. Globalseg *g;
  454. uintptr_t va, len, top;
  455. int i;
  456. struct{
  457. char *name;
  458. int type;
  459. }segs[] = {
  460. {"kmsg", SG_SHARED|SG_ZIO|SG_KZIO},
  461. {"umsg", SG_SHARED|SG_ZIO},
  462. {"addr", SG_SHARED},
  463. };
  464. if(c->qid.type == QTDIR)
  465. error(Eperm);
  466. switch(TYPE(c)){
  467. case Qfree:
  468. error(Eperm);
  469. break;
  470. case Qctl:
  471. g = c->aux;
  472. cb = parsecmd(a, n);
  473. for(i = 0; i < nelem(segs); i++)
  474. if(strcmp(cb->f[0], segs[i].name) == 0)
  475. break;
  476. if(i < nelem(segs)){
  477. if(g->s != nil)
  478. error("already has a virtual address");
  479. if(cb->nf < 3)
  480. cmderror(cb, Ebadarg);
  481. va = strtoul(cb->f[1], 0, 0);
  482. len = strtoul(cb->f[2], 0, 0);
  483. if(va == 0)
  484. va = placeseg(len);
  485. top = BIGPGROUND(va + len);
  486. va = va&~(BIGPGSZ-1);
  487. len = (top - va) / BIGPGSZ;
  488. if(len == 0)
  489. cmderror(cb, "empty segment");
  490. g->s = newseg(segs[i].type, va, len);
  491. if(i == 0)
  492. newzmap(g->s);
  493. else if(i == 1)
  494. zgrow(g->s);
  495. DBG("newseg %s base %#llx len %#llx\n",
  496. cb->f[0], va, len*BIGPGSZ);
  497. if(i == 0 || i == 1)
  498. dumpzseg(g->s);
  499. }else if(strcmp(cb->f[0], "heap") == 0){
  500. if(g == nil)
  501. error("no globalseg");
  502. if(g->s == nil)
  503. error("no segment");
  504. if(heapseg)
  505. error("heap already set");
  506. else
  507. heapseg = g->s;
  508. }else
  509. error(Ebadctl);
  510. break;
  511. case Qdata:
  512. g = c->aux;
  513. if(voff < 0)
  514. error(Enegoff);
  515. if(voff + n > g->s->top - g->s->base){
  516. n = g->s->top - voff;
  517. if(n <= 0)
  518. break;
  519. }
  520. qlock(&g->ql);
  521. if(waserror()){
  522. qunlock(&g->ql);
  523. nexterror();
  524. }
  525. g->off = voff + g->s->base;
  526. g->data = smalloc(n);
  527. if(waserror()){
  528. free(g->data);
  529. nexterror();
  530. }
  531. g->dlen = n;
  532. memmove(g->data, a, g->dlen);
  533. docmd(g, Cwrite);
  534. poperror();
  535. free(g->data);
  536. poperror();
  537. qunlock(&g->ql);
  538. break;
  539. default:
  540. panic("segmentwrite");
  541. }
  542. return n;
  543. }
  544. static int32_t
  545. segmentwstat(Chan *c, uint8_t *dp, int32_t n)
  546. {
  547. Proc *up = externup();
  548. Globalseg *g;
  549. Dir *d;
  550. if(c->qid.type == QTDIR)
  551. error(Eperm);
  552. g = getgseg(c);
  553. if(waserror()){
  554. putgseg(g);
  555. nexterror();
  556. }
  557. if(strcmp(g->uid, up->user)!=0 && !iseve())
  558. error(Eperm);
  559. d = smalloc(sizeof(Dir)+n);
  560. if(waserror()){
  561. free(d);
  562. nexterror();
  563. }
  564. n = convM2D(dp, n, &d[0], (char*)&d[1]);
  565. if(!emptystr(d->uid) && strcmp(d->uid, g->uid) != 0)
  566. kstrdup(&g->uid, d->uid);
  567. if(d->mode != (uint32_t)~0UL)
  568. g->perm = d->mode & 0777;
  569. poperror();
  570. free(d);
  571. poperror();
  572. putgseg(g);
  573. return n;
  574. }
  575. static void
  576. segmentremove(Chan *c)
  577. {
  578. Globalseg *g;
  579. int x;
  580. if(TYPE(c) != Qsegdir)
  581. error(Eperm);
  582. lock(&globalseglock);
  583. x = SEG(c);
  584. g = globalseg[x];
  585. globalseg[x] = nil;
  586. unlock(&globalseglock);
  587. if(g != nil)
  588. putgseg(g);
  589. }
  590. /*
  591. * called by segattach()
  592. */
  593. static Segment*
  594. globalsegattach(Proc *p, char *name)
  595. {
  596. Proc *up = externup();
  597. int x;
  598. Globalseg *g;
  599. Segment *s;
  600. g = nil;
  601. if(waserror()){
  602. unlock(&globalseglock);
  603. nexterror();
  604. }
  605. lock(&globalseglock);
  606. for(x = 0; x < nelem(globalseg); x++){
  607. g = globalseg[x];
  608. if(g != nil && strcmp(g->name, name) == 0)
  609. break;
  610. }
  611. if(x == nelem(globalseg)){
  612. unlock(&globalseglock);
  613. poperror();
  614. return nil;
  615. }
  616. devpermcheck(g->uid, g->perm, ORDWR);
  617. s = g->s;
  618. if(s == nil)
  619. error("global segment not assigned a virtual address");
  620. if(isoverlap(p, s->base, s->top - s->base) != nil)
  621. error("overlaps existing segment");
  622. incref(&s->r);
  623. unlock(&globalseglock);
  624. poperror();
  625. return s;
  626. }
  627. static void
  628. docmd(Globalseg *g, int cmd)
  629. {
  630. Proc *up = externup();
  631. g->err[0] = 0;
  632. g->cmd = cmd;
  633. wakeup(&g->cmdwait);
  634. while(waserror())
  635. {} /* no interrupts */
  636. sleep(&g->replywait, cmddone, g);
  637. poperror();
  638. if(g->err[0])
  639. error(g->err);
  640. }
  641. static int
  642. cmdready(void *arg)
  643. {
  644. Globalseg *g = arg;
  645. return g->cmd != Cnone;
  646. }
  647. /*
  648. * TO DO: better approach is to send segment with command,
  649. * temporarily add it to segment array at SEG1, do the operation, then putseg.
  650. * otherwise there are as many kprocs as segments.
  651. */
  652. static void
  653. segmentkproc(void *arg)
  654. {
  655. Proc *up = externup();
  656. Globalseg *g = arg;
  657. int done;
  658. int sno;
  659. qlock(&up->seglock);
  660. for(sno = 0; sno < NSEG; sno++)
  661. if(up->seg[sno] == nil)
  662. break;
  663. if(sno == NSEG)
  664. panic("segmentkproc");
  665. g->kproc = up;
  666. incref(&g->s->r);
  667. up->seg[sno] = g->s;
  668. qunlock(&up->seglock);
  669. for(done = 0; !done;){
  670. sleep(&g->cmdwait, cmdready, g);
  671. if(waserror()){
  672. strncpy(g->err, up->errstr, sizeof(g->err));
  673. } else {
  674. switch(g->cmd){
  675. case Cstart:
  676. break;
  677. case Cdie:
  678. done = 1;
  679. break;
  680. case Cread:
  681. memmove(g->data, (char*)g->off, g->dlen);
  682. break;
  683. case Cwrite:
  684. memmove((char*)g->off, g->data, g->dlen);
  685. break;
  686. }
  687. poperror();
  688. }
  689. g->cmd = Cnone;
  690. wakeup(&g->replywait);
  691. }
  692. }
  693. Dev segmentdevtab = {
  694. .dc = 'g',
  695. .name = "segment",
  696. .reset = devreset,
  697. .init = segmentinit,
  698. .shutdown = devshutdown,
  699. .attach = segmentattach,
  700. .walk = segmentwalk,
  701. .stat = segmentstat,
  702. .open = segmentopen,
  703. .create = segmentcreate,
  704. .close = segmentclose,
  705. .read = segmentread,
  706. .bread = devbread,
  707. .write = segmentwrite,
  708. .bwrite = devbwrite,
  709. .remove = segmentremove,
  710. .wstat = segmentwstat,
  711. };