1
2#include <mini-os/os.h>
3#include <mini-os/xenbus.h>
4#include <mini-os/wait.h>
5
6#include <bmk-core/memalloc.h>
7#include <bmk-core/string.h>
8#include <bmk-core/errno.h>
9
10#include <bmk-rumpuser/core_types.h>
11#include <bmk-rumpuser/rumpuser.h>
12
13#include "busdev_user.h"
14
15#define xbd_malloc(sz) (bmk_memalloc((sz), 0, BMK_MEMWHO_RUMPKERN))
16
17static inline void xbd_free(void *p) { bmk_memfree(p, BMK_MEMWHO_RUMPKERN); }
18
19#define strcmp bmk_strcmp
20#define strlen bmk_strlen
21#define memchr bmk_memchr
22#define memcpy bmk_memcpy
23#define strtoul bmk_strtoul
24
25#define bzero(p,l) bmk_memset((p),0,(l))
26
27#define KASSERT bmk_assert
28#define assert  bmk_assert
29#define INT_MAX ((int)(~(unsigned int)0 >> 1u))
30
31#define ENOMEM BMK_ENOMEM
32#define EINVAL BMK_EINVAL
33
34#define printf minios_printk
35
36#ifdef RUMP_DEV_XEN_DEBUG
37#define DPRINTF(a) (printf a)
38#else
39#define DPRINTF(a) /* nothing */
40#endif
41
42static char *xbd_strdup(const char *s) {
43	size_t l = strlen(s);
44	char *r = xbd_malloc(l + 1);
45	if (!r) return r;
46	memcpy(r, s, l+1);
47	return r;
48}
49
50/*----- data structures -----*/
51
52struct xenbus_dev_request {
53	struct xenbus_event xb;
54	uint32_t xb_id, user_id;
55	uint32_t req_type;
56	union {
57		struct xenbus_dev_transaction *trans;
58		struct xenbus_dev_watch *watch;
59	} u;
60};
61
62struct xenbus_dev_transaction {
63	LIST_ENTRY(xenbus_dev_transaction) entry;
64	xenbus_transaction_t tx_id;
65	struct xenbus_dev_request destroy;
66};
67
68struct xenbus_dev_watch {
69	struct xenbus_watch xb;
70	LIST_ENTRY(xenbus_dev_watch) entry;
71	struct xsd_sockmsg *wmsg;
72	char *path, *user_token;
73	_Bool visible_to_user;
74	struct xenbus_dev_request destroy;
75};
76
77struct rumpxenbus_data_user {
78	struct rumpxenbus_data_common *c;
79	int outstanding_requests;
80	LIST_HEAD(, xenbus_dev_transaction) transactions;
81	LIST_HEAD(, xenbus_dev_watch) watches;
82	struct xenbus_event_queue replies; /* Entirely unread by user. */
83};
84
85/*----- helpers -----*/
86
87static void
88free_watch(struct xenbus_dev_watch *watch)
89{
90	xbd_free(watch->path);
91	xbd_free(watch->user_token);
92	xbd_free(watch);
93}
94
95static struct xenbus_dev_transaction*
96find_transaction(struct rumpxenbus_data_common *dc, xenbus_transaction_t id)
97{
98	struct rumpxenbus_data_user *const du = dc->du;
99	struct xenbus_dev_transaction *trans;
100
101	LIST_FOREACH(trans, &du->transactions, entry)
102		if (trans->tx_id == dc->wbuf.msg.tx_id)
103			return trans;
104	/* not found */
105	return 0;
106}
107
108static struct xenbus_dev_watch*
109find_visible_watch(struct rumpxenbus_data_common *dc,
110		   const char *path, const char *token)
111{
112	struct rumpxenbus_data_user *const du = dc->du;
113	struct xenbus_dev_watch *watch;
114
115	LIST_FOREACH(watch, &du->watches, entry)
116		if (watch->visible_to_user &&
117		    !strcmp(path, watch->path) &&
118		    !strcmp(token, watch->user_token))
119			return watch;
120	/* not found */
121	return 0;
122}
123
124/*----- request handling (writes to the device) -----*/
125
126static void
127make_request(struct rumpxenbus_data_common *dc, struct xenbus_dev_request *req,
128	     uint32_t tx_id, const struct write_req *wreqs, int num_wreqs)
129/* Caller should have filled in req->req_id, ->u, and (if needed)
130 * ->user_id.  We deal with ->xb and ->xb_id. */
131{
132	struct rumpxenbus_data_user *const du = dc->du;
133
134	req->xb.watch = 0;
135	req->xb_id = xenbus_id_allocate(&du->replies, &req->xb);
136
137	KASSERT(du->outstanding_requests < INT_MAX);
138	du->outstanding_requests++;
139
140	xenbus_xb_write(req->req_type, req->xb_id, tx_id,
141			wreqs, num_wreqs);
142}
143
144static void
145watch_write_req_string(struct write_req **wreqp, const char *string)
146{
147	struct write_req *wreq = (*wreqp)++;
148	int l = strlen(string);
149	wreq->len = l+1;
150	wreq->data = string;
151}
152
153static void
154make_watch_request(struct rumpxenbus_data_common *dc,
155		   struct xenbus_dev_request *req,
156		   uint32_t tx_id, struct xenbus_dev_watch *watch)
157{
158	struct write_req wreqs[2], *wreq = wreqs;
159	watch_write_req_string(&wreq, watch->path);
160	watch_write_req_string(&wreq, watch->xb.token);
161	KASSERT((char*)wreq == (char*)wreqs + sizeof(wreqs));
162
163	req->u.watch = watch;
164	make_request(dc, req, tx_id, wreqs, 2);
165}
166
167static void
168forward_request(struct rumpxenbus_data_common *dc, struct xenbus_dev_request *req)
169{
170	struct write_req wreq = {
171		dc->wbuf.buffer + sizeof(dc->wbuf.msg),
172		dc->wbuf_used - sizeof(dc->wbuf.msg),
173	};
174
175	make_request(dc, req, dc->wbuf.msg.tx_id, &wreq, 1);
176}
177
178static _Bool
179watch_message_parse_string(const char **p, const char *end,
180			   const char **string_r)
181{
182	const char *nul = memchr(*p, 0, end - *p);
183	if (!nul)
184		return 0;
185
186	*string_r = *p;
187	*p = nul+1;
188
189	return 1;
190}
191
192static _Bool
193watch_message_parse(const struct xsd_sockmsg *msg,
194		    const char **path_r, const char **token_r)
195{
196	const char *begin = (const char*)msg;
197	const char *p = begin + sizeof(*msg);
198	const char *end = p + msg->len;
199	KASSERT(p <= end);
200
201	return
202		watch_message_parse_string(&p, end, path_r) &&
203		watch_message_parse_string(&p, end, token_r);
204}
205
206int
207rumpxenbus_process_request(struct rumpxenbus_data_common *dc)
208{
209	struct rumpxenbus_data_user *const du = dc->du;
210	struct xenbus_dev_request *req;
211	struct xenbus_dev_transaction *trans;
212	struct xenbus_dev_watch *watch_free = 0, *watch;
213	const char *wpath, *wtoken;
214	int err;
215
216	DPRINTF(("/dev/xen/xenbus[%p,du=%p]: request, type=%d\n",
217		 dc,du, dc->wbuf.msg.type));
218
219	req = xbd_malloc(sizeof(*req));
220	if (!req) {
221		err = ENOMEM;
222		goto end;
223	}
224	req->user_id = dc->wbuf.msg.req_id;
225	req->req_type = dc->wbuf.msg.type;
226
227	switch (dc->wbuf.msg.type) {
228	case XS_DIRECTORY:
229	case XS_READ:
230	case XS_GET_PERMS:
231	case XS_GET_DOMAIN_PATH:
232	case XS_IS_DOMAIN_INTRODUCED:
233	case XS_WRITE:
234	case XS_MKDIR:
235	case XS_RM:
236	case XS_SET_PERMS:
237		if (dc->wbuf.msg.tx_id) {
238			if (!find_transaction(dc, dc->wbuf.msg.tx_id))
239				WTROUBLE("unknown transaction");
240		}
241		forward_request(dc, req);
242		break;
243
244	case XS_TRANSACTION_START:
245		if (dc->wbuf.msg.tx_id)
246			WTROUBLE("nested transaction");
247		req->u.trans = xbd_malloc(sizeof(*req->u.trans));
248		if (!req->u.trans) {
249			err = ENOMEM;
250			goto end;
251		}
252		forward_request(dc, req);
253		break;
254
255	case XS_TRANSACTION_END:
256		if (!dc->wbuf.msg.tx_id)
257			WTROUBLE("ending zero transaction");
258		req->u.trans = trans = find_transaction(dc, dc->wbuf.msg.tx_id);
259		if (!trans)
260			WTROUBLE("ending unknown transaction");
261		LIST_REMOVE(trans, entry); /* prevent more reqs using it */
262		forward_request(dc, req);
263		break;
264
265	case XS_WATCH:
266		if (dc->wbuf.msg.tx_id)
267			WTROUBLE("XS_WATCH with transaction");
268		if (!watch_message_parse(&dc->wbuf.msg, &wpath, &wtoken))
269			WTROUBLE("bad XS_WATCH message");
270
271		watch = watch_free = xbd_malloc(sizeof(*watch));
272		if (!watch) {
273			err = ENOMEM;
274			goto end;
275		}
276
277		watch->path = xbd_strdup(wpath);
278		watch->user_token = xbd_strdup(wtoken);
279		if (!watch->path || !watch->user_token) {
280			err = ENOMEM;
281			goto end;
282		}
283
284		watch->xb.events = &du->replies;
285		xenbus_watch_prepare(&watch->xb);
286
287		watch_free = 0; /* we are committed */
288		watch->visible_to_user = 0;
289		LIST_INSERT_HEAD(&du->watches, watch, entry);
290		make_watch_request(dc, req, dc->wbuf.msg.tx_id, watch);
291		break;
292
293	case XS_UNWATCH:
294		if (dc->wbuf.msg.tx_id)
295			WTROUBLE("XS_UNWATCH with transaction");
296		if (!watch_message_parse(&dc->wbuf.msg, &wpath, &wtoken))
297			WTROUBLE("bad XS_WATCH message");
298
299		watch = find_visible_watch(dc, wpath, wtoken);
300		if (!watch)
301			WTROUBLE("unwatch nonexistent watch");
302
303		watch->visible_to_user = 0;
304		make_watch_request(dc, req, dc->wbuf.msg.tx_id, watch);
305		break;
306
307	default:
308		WTROUBLE("unknown request message type");
309	}
310
311	err = 0;
312end:
313	if (watch_free)
314		free_watch(watch_free);
315	return err;
316}
317
318/*----- response and watch event handling (reads from the device) -----*/
319
320static struct xsd_sockmsg*
321process_watch_event(struct rumpxenbus_data_common *dc, struct xenbus_event *event,
322		    struct xenbus_dev_watch *watch,
323		    void (**mfree_r)(void*))
324{
325
326	/* We need to make a new XS_WATCH_EVENT message because the
327	 * one from xenstored (a) isn't visible to us here and (b)
328	 * anyway has the wrong token in it. */
329
330	DPRINTF(("/dev/xen/xenbus[%p]: watch event,"
331		 " wpath=%s user_token=%s epath=%s xb.token=%s\n",
332                 dc,
333		 watch->path, watch->user_token,
334		 event->path, watch->xb.token));
335
336	/* Define the parts of the message */
337
338#define WATCH_MESSAGE_PART_STRING(PART,x)		\
339	PART(strlen((x)) + 1, memcpy(p, (x), sz))
340
341#define WATCH_MESSAGE_PARTS(PART)				\
342	PART(sizeof(struct xsd_sockmsg), (void)0)		\
343	WATCH_MESSAGE_PART_STRING(PART,event->path)		\
344	WATCH_MESSAGE_PART_STRING(PART,watch->user_token)
345
346	/* Compute the size */
347
348	size_t totalsz = 0;
349	size_t sz = 0;
350
351#define WATCH_MESSAGE_PART_ADD_SIZE(calcpartsz, fill) \
352	totalsz += (calcpartsz);
353
354	WATCH_MESSAGE_PARTS(WATCH_MESSAGE_PART_ADD_SIZE);
355
356	DPRINTF(("/dev/xen/xenbus: watch event allocating %lu\n",
357		 (unsigned long)totalsz));
358
359	/* Allocate it and fill in the header */
360
361	struct xsd_sockmsg *reply = xbd_malloc(totalsz);
362	if (!reply) {
363		printf("xenbus dev: out of memory for watch event"
364		       " wpath=`%s' epath=`%s'\n",
365		       watch->path, event->path);
366		dc->queued_enomem = 1;
367		goto end;
368	}
369
370	bzero(reply, sizeof(*reply));
371	reply->type = XS_WATCH_EVENT;
372	reply->len = totalsz - sizeof(*reply);
373
374	char *p = (void*)reply;
375
376	/* Fill in the rest of the message */
377
378#define WATCH_MESSAGE_PART_ADD(calcpartsz, fill)	\
379	sz = (calcpartsz);				\
380	fill;						\
381	p += sz;
382
383	WATCH_MESSAGE_PARTS(WATCH_MESSAGE_PART_ADD);
384
385	KASSERT(p == (const char*)reply + totalsz);
386
387	/* Now we are done */
388
389end:
390	xenbus_free(event);
391	*mfree_r = xbd_free;
392	return reply;
393}
394
395/* Returned value is from malloc() */
396static struct xsd_sockmsg*
397process_response(struct rumpxenbus_data_common *dc, struct xenbus_dev_request *req,
398		 void (**mfree_r)(void*))
399{
400	struct rumpxenbus_data_user *const du = dc->du;
401	struct xenbus_dev_watch *watch;
402	struct xsd_sockmsg *msg = req->xb.reply;
403
404	msg->req_id = req->user_id;
405
406	_Bool error = msg->type == XS_ERROR;
407	KASSERT(error || msg->type == req->req_type);
408
409	DPRINTF(("/dev/xen/xenbus[%p,du=%p]:"
410                 " response, req_type=%d msg->type=%d\n",
411		 dc,du, req->req_type, msg->type));
412
413	switch (req->req_type) {
414
415	case XS_TRANSACTION_START:
416		if (error)
417			break;
418		KASSERT(msg->len >= 2);
419		KASSERT(!((uint8_t*)(msg+1))[msg->len-1]);
420		req->u.trans->tx_id =
421			strtoul((char*)&msg + sizeof(*msg),
422				0, 0);
423		LIST_INSERT_HEAD(&du->transactions, req->u.trans,
424				 entry);
425		break;
426
427	case XS_TRANSACTION_END:
428		xbd_free(req->u.trans);
429		break;
430
431	case XS_WATCH:
432		watch = req->u.watch;
433		if (error)
434			goto do_unwatch;
435		watch->visible_to_user = 1;
436		break;
437
438	case XS_UNWATCH:
439		KASSERT(!error);
440		watch = req->u.watch;
441	do_unwatch:
442		KASSERT(!watch->visible_to_user);
443		LIST_REMOVE(watch, entry);
444		xenbus_watch_release(&watch->xb);
445		free_watch(watch);
446		break;
447
448	}
449
450	xenbus_id_release(req->xb_id);
451	xbd_free(req);
452	KASSERT(du->outstanding_requests > 0);
453	du->outstanding_requests--;
454
455	*mfree_r = xenbus_free;
456	return msg;
457}
458
459static struct xsd_sockmsg*
460process_event(struct rumpxenbus_data_common *dc, struct xenbus_event *event,
461	      void (**mfree_r)(void*))
462{
463	if (event->watch) {
464		struct xenbus_dev_watch *watch =
465			container_of(event->watch, struct xenbus_dev_watch, xb);
466
467		return process_watch_event(dc, event, watch, mfree_r);
468
469	} else {
470		struct xenbus_dev_request *req =
471			container_of(event, struct xenbus_dev_request, xb);
472
473		return process_response(dc, req, mfree_r);
474	}
475
476}
477
478struct xsd_sockmsg*
479rumpxenbus_next_event_msg(struct rumpxenbus_data_common *dc,
480			 _Bool block,
481			 void (**mfree_r)(void*))
482/* If !!block, always blocks and always returns successfully.
483 * If !block, stores err_r_if_nothing into *err_r rather than blocking.
484
485 * If !!err_r, will block iff user process read should block:
486 * will either return successfully, or set *err_r and return 0.
487 *
488 * Must be called with dd->lock held; may temporarily release it
489 * by calling rumpxenbus_block_{before,after}. */
490{
491	struct rumpxenbus_data_user *du = dc->du;
492	int nlocks;
493	DEFINE_WAIT(w);
494	spin_lock(&xenbus_req_lock);
495
496	while (STAILQ_EMPTY(&du->replies.events)) {
497		if (!block)
498			goto fail;
499
500		DPRINTF(("/dev/xen/xenbus[%p,du=%p]: about to block\n",dc,du));
501
502		minios_add_waiter(w, du->replies.waitq);
503		spin_unlock(&xenbus_req_lock);
504		rumpxenbus_block_before(dc);
505		rumpkern_unsched(&nlocks, 0);
506
507		minios_wait(w);
508
509		rumpkern_sched(nlocks, 0);
510		rumpxenbus_block_after(dc);
511		spin_lock(&xenbus_req_lock);
512		minios_remove_waiter(w, du->replies.waitq);
513	}
514	struct xenbus_event *event = STAILQ_FIRST(&du->replies.events);
515	STAILQ_REMOVE_HEAD(&du->replies.events, entry);
516
517	spin_unlock(&xenbus_req_lock);
518
519	DPRINTF(("/dev/xen/xenbus: next_event_msg found an event %p\n",event));
520	return process_event(dc, event, mfree_r);
521
522fail:
523	DPRINTF(("/dev/xen/xenbus: not blocking, returning no event\n"));
524	spin_unlock(&xenbus_req_lock);
525	return 0;
526}
527
528/*----- more exciting reading -----*/
529
530static void
531xenbus_dev_xb_wakeup(struct xenbus_event_queue *queue)
532{
533	/* called with req_lock held */
534	struct rumpxenbus_data_user *du =
535		container_of(queue, struct rumpxenbus_data_user, replies);
536	DPRINTF(("/dev/xen/xenbus[queue=%p,du=%p]: wakeup...\n",queue,du));
537	minios_wake_up(&du->replies.waitq);
538	rumpxenbus_dev_xb_wakeup(du->c);
539}
540
541void
542rumpxenbus_dev_restart_wakeup(struct rumpxenbus_data_common *dc)
543{
544	struct rumpxenbus_data_user *du = dc->du;
545	spin_lock(&xenbus_req_lock);
546	minios_wake_up(&du->replies.waitq);
547	spin_unlock(&xenbus_req_lock);
548}
549
550void
551rumpxenbus_dev_user_shutdown(struct rumpxenbus_data_common *dc)
552{
553	struct rumpxenbus_data_user *du = dc->du;
554	for (;;) {
555		DPRINTF(("/dev/xen/xenbus[%p,du=%p]: close loop\n",dc,du));
556		/* We need to go round this again and again because
557		 * there might be requests in flight.  Eg if the
558		 * user has an XS_WATCH in flight we have to wait for it
559		 * to be done and then unwatch it again. */
560
561		struct xenbus_dev_watch *watch, *watch_tmp;
562		LIST_FOREACH_SAFE(watch, &du->watches, entry, watch_tmp) {
563			DPRINTF(("/dev/xen/xenbus: close watch %p %d\n",
564				 watch, watch->visible_to_user));
565			if (watch->visible_to_user) {
566				/* mirrors process_request XS_UNWATCH */
567				watch->destroy.req_type = XS_UNWATCH;
568				watch->visible_to_user = 0;
569				make_watch_request(dc, &watch->destroy, 0,
570						   watch);
571			}
572		}
573
574		struct xenbus_dev_transaction *trans, *trans_tmp;
575		const struct write_req trans_end_data = { "F", 2 };
576		LIST_FOREACH_SAFE(trans, &du->transactions, entry, trans_tmp) {
577			DPRINTF(("/dev/xen/xenbus: close transaction"
578				 " %p %lx\n",
579				 trans, (unsigned long)trans->tx_id));
580			/* mirrors process_request XS_TRANSACTION_END */
581			trans->destroy.req_type = XS_TRANSACTION_END;
582			trans->destroy.u.trans = trans;
583			LIST_REMOVE(trans, entry);
584			make_request(dc, &trans->destroy, trans->tx_id,
585				     &trans_end_data, 1);
586		}
587
588		DPRINTF(("/dev/xen/xenbus: close outstanding=%d\n",
589			 du->outstanding_requests));
590		KASSERT(du->outstanding_requests >= 0);
591		if (!du->outstanding_requests)
592			break;
593
594		void (*dfree)(void*);
595
596		struct xsd_sockmsg *discard =
597			rumpxenbus_next_event_msg(dc, 1, &dfree);
598
599		KASSERT(discard);
600		dfree(discard);
601	}
602
603	KASSERT(!du->outstanding_requests);
604	KASSERT(LIST_EMPTY(&du->transactions));
605	KASSERT(LIST_EMPTY(&du->watches));
606
607	xbd_free(du);
608	dc->du = NULL;
609}
610
611int
612rumpxenbus_dev_user_open(struct rumpxenbus_data_common *dc)
613{
614	assert(!dc->du);
615
616	struct rumpxenbus_data_user *du = dc->du = xbd_malloc(sizeof(*dc->du));
617	if (!du)
618		return ENOMEM;
619
620	DPRINTF(("/dev/xen/xenbus[%p,dd=%p]: open: user...\n",dc,du));
621
622	du->c = dc;
623	du->outstanding_requests = 0;
624	LIST_INIT(&du->transactions);
625	LIST_INIT(&du->watches);
626	xenbus_event_queue_init(&du->replies);
627	du->replies.wakeup = xenbus_dev_xb_wakeup;
628
629	dc->wbuf_used = 0;
630	dc->queued_enomem = 0;
631
632	return 0;
633}
634