debuggers.hg

view extras/mini-os/fbfront.c @ 20689:23bc248302df

mini-os: Fix memory leaks in blkfront, netfront, pcifront, etc.

The return value of Xenbus routines xenbus_transaction_start(),
xenbus_printf(), xenbus_transaction_end(), etc. is a pointer of error
message. This pointer should be passed to free() to release the
allocated memory when it is no longer needed.

Signed-off-by: Yu Zhiguo <yuzg@cn.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Dec 14 09:51:07 2009 +0000 (2009-12-14)
parents 005bd672d3af
children b20f897d6010
line source
1 /*
2 * Frame Buffer + Keyboard driver for Mini-OS.
3 * Samuel Thibault <samuel.thibault@eu.citrix.com>, 2008
4 * Based on blkfront.c.
5 */
7 #include <mini-os/os.h>
8 #include <mini-os/xenbus.h>
9 #include <mini-os/events.h>
10 #include <xen/io/kbdif.h>
11 #include <xen/io/fbif.h>
12 #include <xen/io/protocols.h>
13 #include <mini-os/gnttab.h>
14 #include <mini-os/xmalloc.h>
15 #include <mini-os/fbfront.h>
16 #include <mini-os/lib.h>
18 DECLARE_WAIT_QUEUE_HEAD(kbdfront_queue);
25 struct kbdfront_dev {
26 domid_t dom;
28 struct xenkbd_page *page;
29 evtchn_port_t evtchn;
31 char *nodename;
32 char *backend;
34 xenbus_event_queue events;
36 #ifdef HAVE_LIBC
37 int fd;
38 #endif
39 };
41 void kbdfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
42 {
43 #ifdef HAVE_LIBC
44 struct kbdfront_dev *dev = data;
45 int fd = dev->fd;
47 if (fd != -1)
48 files[fd].read = 1;
49 #endif
50 wake_up(&kbdfront_queue);
51 }
53 static void free_kbdfront(struct kbdfront_dev *dev)
54 {
55 mask_evtchn(dev->evtchn);
57 free(dev->backend);
59 free_page(dev->page);
61 unbind_evtchn(dev->evtchn);
63 free(dev->nodename);
64 free(dev);
65 }
67 struct kbdfront_dev *init_kbdfront(char *_nodename, int abs_pointer)
68 {
69 xenbus_transaction_t xbt;
70 char* err;
71 char* message=NULL;
72 struct xenkbd_page *s;
73 int retry=0;
74 char* msg = NULL;
75 char* nodename = _nodename ? _nodename : "device/vkbd/0";
76 struct kbdfront_dev *dev;
78 char path[strlen(nodename) + 1 + 10 + 1];
80 printk("******************* KBDFRONT for %s **********\n\n\n", nodename);
82 dev = malloc(sizeof(*dev));
83 memset(dev, 0, sizeof(*dev));
84 dev->nodename = strdup(nodename);
85 #ifdef HAVE_LIBC
86 dev->fd = -1;
87 #endif
89 snprintf(path, sizeof(path), "%s/backend-id", nodename);
90 dev->dom = xenbus_read_integer(path);
91 evtchn_alloc_unbound(dev->dom, kbdfront_handler, dev, &dev->evtchn);
93 dev->page = s = (struct xenkbd_page*) alloc_page();
94 memset(s,0,PAGE_SIZE);
96 dev->events = NULL;
98 s->in_cons = s->in_prod = 0;
99 s->out_cons = s->out_prod = 0;
101 again:
102 err = xenbus_transaction_start(&xbt);
103 if (err) {
104 printk("starting transaction\n");
105 free(err);
106 }
108 err = xenbus_printf(xbt, nodename, "page-ref","%u", virt_to_mfn(s));
109 if (err) {
110 message = "writing page-ref";
111 goto abort_transaction;
112 }
113 err = xenbus_printf(xbt, nodename, "event-channel", "%u", dev->evtchn);
114 if (err) {
115 message = "writing event-channel";
116 goto abort_transaction;
117 }
118 if (abs_pointer) {
119 err = xenbus_printf(xbt, nodename, "request-abs-pointer", "1");
120 if (err) {
121 message = "writing event-channel";
122 goto abort_transaction;
123 }
124 }
126 snprintf(path, sizeof(path), "%s/state", nodename);
127 err = xenbus_switch_state(xbt, path, XenbusStateInitialised);
128 if (err) {
129 printk("error writing initialized: %s\n", err);
130 free(err);
131 }
133 err = xenbus_transaction_end(xbt, 0, &retry);
134 if (err) free(err);
135 if (retry) {
136 goto again;
137 printk("completing transaction\n");
138 }
140 goto done;
142 abort_transaction:
143 free(err);
144 err = xenbus_transaction_end(xbt, 1, &retry);
145 goto error;
147 done:
149 snprintf(path, sizeof(path), "%s/backend", nodename);
150 msg = xenbus_read(XBT_NIL, path, &dev->backend);
151 if (msg) {
152 printk("Error %s when reading the backend path %s\n", msg, path);
153 goto error;
154 }
156 printk("backend at %s\n", dev->backend);
158 {
159 XenbusState state;
160 char path[strlen(dev->backend) + 1 + 6 + 1];
161 char frontpath[strlen(nodename) + 1 + 6 + 1];
163 snprintf(path, sizeof(path), "%s/state", dev->backend);
165 xenbus_watch_path_token(XBT_NIL, path, path, &dev->events);
167 err = NULL;
168 state = xenbus_read_integer(path);
169 while (err == NULL && state < XenbusStateConnected)
170 err = xenbus_wait_for_state_change(path, &state, &dev->events);
171 if (state != XenbusStateConnected) {
172 printk("backend not available, state=%d\n", state);
173 xenbus_unwatch_path_token(XBT_NIL, path, path);
174 goto error;
175 }
177 printk("%s connected\n", dev->backend);
179 snprintf(frontpath, sizeof(frontpath), "%s/state", nodename);
180 if((err = xenbus_switch_state(XBT_NIL, frontpath, XenbusStateConnected))
181 != NULL) {
182 printk("error switching state: %s\n", err);
183 xenbus_unwatch_path_token(XBT_NIL, path, path);
184 goto error;
185 }
186 }
187 unmask_evtchn(dev->evtchn);
189 printk("************************** KBDFRONT\n");
191 return dev;
192 error:
193 free(msg);
194 free(err);
195 free_kbdfront(dev);
196 return NULL;
197 }
199 int kbdfront_receive(struct kbdfront_dev *dev, union xenkbd_in_event *buf, int n)
200 {
201 struct xenkbd_page *page = dev->page;
202 uint32_t prod, cons;
203 int i;
205 #ifdef HAVE_LIBC
206 if (dev->fd != -1) {
207 files[dev->fd].read = 0;
208 mb(); /* Make sure to let the handler set read to 1 before we start looking at the ring */
209 }
210 #endif
212 prod = page->in_prod;
214 if (prod == page->in_cons)
215 return 0;
217 rmb(); /* ensure we see ring contents up to prod */
219 for (i = 0, cons = page->in_cons; i < n && cons != prod; i++, cons++)
220 memcpy(buf + i, &XENKBD_IN_RING_REF(page, cons), sizeof(*buf));
222 mb(); /* ensure we got ring contents */
223 page->in_cons = cons;
224 notify_remote_via_evtchn(dev->evtchn);
226 #ifdef HAVE_LIBC
227 if (cons != prod && dev->fd != -1)
228 /* still some events to read */
229 files[dev->fd].read = 1;
230 #endif
232 return i;
233 }
236 void shutdown_kbdfront(struct kbdfront_dev *dev)
237 {
238 char* err = NULL;
239 XenbusState state;
241 char path[strlen(dev->backend) + 1 + 5 + 1];
242 char nodename[strlen(dev->nodename) + 1 + 5 + 1];
244 printk("close kbd: backend at %s\n",dev->backend);
246 snprintf(path, sizeof(path), "%s/state", dev->backend);
247 snprintf(nodename, sizeof(nodename), "%s/state", dev->nodename);
248 if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosing)) != NULL) {
249 printk("shutdown_kbdfront: error changing state to %d: %s\n",
250 XenbusStateClosing, err);
251 goto close_kbdfront;
252 }
253 state = xenbus_read_integer(path);
254 while (err == NULL && state < XenbusStateClosing)
255 err = xenbus_wait_for_state_change(path, &state, &dev->events);
256 if (err) free(err);
258 if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosed)) != NULL) {
259 printk("shutdown_kbdfront: error changing state to %d: %s\n",
260 XenbusStateClosed, err);
261 goto close_kbdfront;
262 }
263 state = xenbus_read_integer(path);
264 if (state < XenbusStateClosed) {
265 err = xenbus_wait_for_state_change(path, &state, &dev->events);
266 if (err) free(err);
267 }
269 if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateInitialising)) != NULL) {
270 printk("shutdown_kbdfront: error changing state to %d: %s\n",
271 XenbusStateInitialising, err);
272 goto close_kbdfront;
273 }
274 // does not work yet.
275 //xenbus_wait_for_value(path, "2", &dev->events);
277 close_kbdfront:
278 if (err) free(err);
279 xenbus_unwatch_path_token(XBT_NIL, path, path);
281 snprintf(path, sizeof(path), "%s/page-ref", nodename);
282 xenbus_rm(XBT_NIL, path);
283 snprintf(path, sizeof(path), "%s/event-channel", nodename);
284 xenbus_rm(XBT_NIL, path);
285 snprintf(path, sizeof(path), "%s/request-abs-pointer", nodename);
286 xenbus_rm(XBT_NIL, path);
288 free_kbdfront(dev);
289 }
291 #ifdef HAVE_LIBC
292 int kbdfront_open(struct kbdfront_dev *dev)
293 {
294 dev->fd = alloc_fd(FTYPE_KBD);
295 printk("kbd_open(%s) -> %d\n", dev->nodename, dev->fd);
296 files[dev->fd].kbd.dev = dev;
297 return dev->fd;
298 }
299 #endif
305 DECLARE_WAIT_QUEUE_HEAD(fbfront_queue);
312 struct fbfront_dev {
313 domid_t dom;
315 struct xenfb_page *page;
316 evtchn_port_t evtchn;
318 char *nodename;
319 char *backend;
320 int request_update;
322 int width;
323 int height;
324 int depth;
325 int stride;
326 int mem_length;
327 int offset;
329 xenbus_event_queue events;
331 #ifdef HAVE_LIBC
332 int fd;
333 #endif
334 };
336 void fbfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
337 {
338 #ifdef HAVE_LIBC
339 struct fbfront_dev *dev = data;
340 int fd = dev->fd;
342 if (fd != -1)
343 files[fd].read = 1;
344 #endif
345 wake_up(&fbfront_queue);
346 }
348 static void free_fbfront(struct fbfront_dev *dev)
349 {
350 mask_evtchn(dev->evtchn);
352 free(dev->backend);
354 free_page(dev->page);
356 unbind_evtchn(dev->evtchn);
358 free(dev->nodename);
359 free(dev);
360 }
362 int fbfront_receive(struct fbfront_dev *dev, union xenfb_in_event *buf, int n)
363 {
364 struct xenfb_page *page = dev->page;
365 uint32_t prod, cons;
366 int i;
368 #ifdef HAVE_LIBC
369 if (dev->fd != -1) {
370 files[dev->fd].read = 0;
371 mb(); /* Make sure to let the handler set read to 1 before we start looking at the ring */
372 }
373 #endif
375 prod = page->in_prod;
377 if (prod == page->in_cons)
378 return 0;
380 rmb(); /* ensure we see ring contents up to prod */
382 for (i = 0, cons = page->in_cons; i < n && cons != prod; i++, cons++)
383 memcpy(buf + i, &XENFB_IN_RING_REF(page, cons), sizeof(*buf));
385 mb(); /* ensure we got ring contents */
386 page->in_cons = cons;
387 notify_remote_via_evtchn(dev->evtchn);
389 #ifdef HAVE_LIBC
390 if (cons != prod && dev->fd != -1)
391 /* still some events to read */
392 files[dev->fd].read = 1;
393 #endif
395 return i;
396 }
398 struct fbfront_dev *init_fbfront(char *_nodename, unsigned long *mfns, int width, int height, int depth, int stride, int n)
399 {
400 xenbus_transaction_t xbt;
401 char* err;
402 char* message=NULL;
403 struct xenfb_page *s;
404 int retry=0;
405 char* msg;
406 int i, j;
407 struct fbfront_dev *dev;
408 int max_pd;
409 unsigned long mapped;
410 char* nodename = _nodename ? _nodename : "device/vfb/0";
412 char path[strlen(nodename) + 1 + 10 + 1];
414 printk("******************* FBFRONT for %s **********\n\n\n", nodename);
416 dev = malloc(sizeof(*dev));
417 memset(dev, 0, sizeof(*dev));
418 dev->nodename = strdup(nodename);
419 #ifdef HAVE_LIBC
420 dev->fd = -1;
421 #endif
423 snprintf(path, sizeof(path), "%s/backend-id", nodename);
424 dev->dom = xenbus_read_integer(path);
425 evtchn_alloc_unbound(dev->dom, fbfront_handler, dev, &dev->evtchn);
427 dev->page = s = (struct xenfb_page*) alloc_page();
428 memset(s,0,PAGE_SIZE);
430 s->in_cons = s->in_prod = 0;
431 s->out_cons = s->out_prod = 0;
432 dev->width = s->width = width;
433 dev->height = s->height = height;
434 dev->depth = s->depth = depth;
435 dev->stride = s->line_length = stride;
436 dev->mem_length = s->mem_length = n * PAGE_SIZE;
437 dev->offset = 0;
438 dev->events = NULL;
440 max_pd = sizeof(s->pd) / sizeof(s->pd[0]);
441 mapped = 0;
443 for (i = 0; mapped < n && i < max_pd; i++) {
444 unsigned long *pd = (unsigned long *) alloc_page();
445 for (j = 0; mapped < n && j < PAGE_SIZE / sizeof(unsigned long); j++)
446 pd[j] = mfns[mapped++];
447 for ( ; j < PAGE_SIZE / sizeof(unsigned long); j++)
448 pd[j] = 0;
449 s->pd[i] = virt_to_mfn(pd);
450 }
451 for ( ; i < max_pd; i++)
452 s->pd[i] = 0;
455 again:
456 err = xenbus_transaction_start(&xbt);
457 if (err) {
458 printk("starting transaction\n");
459 free(err);
460 }
462 err = xenbus_printf(xbt, nodename, "page-ref","%u", virt_to_mfn(s));
463 if (err) {
464 message = "writing page-ref";
465 goto abort_transaction;
466 }
467 err = xenbus_printf(xbt, nodename, "event-channel", "%u", dev->evtchn);
468 if (err) {
469 message = "writing event-channel";
470 goto abort_transaction;
471 }
472 err = xenbus_printf(xbt, nodename, "protocol", "%s",
473 XEN_IO_PROTO_ABI_NATIVE);
474 if (err) {
475 message = "writing event-channel";
476 goto abort_transaction;
477 }
478 err = xenbus_printf(xbt, nodename, "feature-update", "1");
479 if (err) {
480 message = "writing event-channel";
481 goto abort_transaction;
482 }
484 snprintf(path, sizeof(path), "%s/state", nodename);
485 err = xenbus_switch_state(xbt, path, XenbusStateInitialised);
486 if (err) {
487 message = "switching state";
488 goto abort_transaction;
489 }
491 err = xenbus_transaction_end(xbt, 0, &retry);
492 if (err) free(err);
493 if (retry) {
494 goto again;
495 printk("completing transaction\n");
496 }
498 goto done;
500 abort_transaction:
501 free(err);
502 err = xenbus_transaction_end(xbt, 1, &retry);
503 goto error;
505 done:
507 snprintf(path, sizeof(path), "%s/backend", nodename);
508 msg = xenbus_read(XBT_NIL, path, &dev->backend);
509 if (msg) {
510 printk("Error %s when reading the backend path %s\n", msg, path);
511 goto error;
512 }
514 printk("backend at %s\n", dev->backend);
516 {
517 XenbusState state;
518 char path[strlen(dev->backend) + 1 + 14 + 1];
519 char frontpath[strlen(nodename) + 1 + 6 + 1];
521 snprintf(path, sizeof(path), "%s/state", dev->backend);
523 xenbus_watch_path_token(XBT_NIL, path, path, &dev->events);
525 err = NULL;
526 state = xenbus_read_integer(path);
527 while (err == NULL && state < XenbusStateConnected)
528 err = xenbus_wait_for_state_change(path, &state, &dev->events);
529 if (state != XenbusStateConnected) {
530 printk("backend not available, state=%d\n", state);
531 xenbus_unwatch_path_token(XBT_NIL, path, path);
532 goto error;
533 }
535 printk("%s connected\n", dev->backend);
537 snprintf(path, sizeof(path), "%s/request-update", dev->backend);
538 dev->request_update = xenbus_read_integer(path);
540 snprintf(frontpath, sizeof(frontpath), "%s/state", nodename);
541 if ((err = xenbus_switch_state(XBT_NIL, frontpath, XenbusStateConnected))
542 != NULL) {
543 printk("error switching state: %s\n", err);
544 xenbus_unwatch_path_token(XBT_NIL, path, path);
545 goto error;
546 }
547 }
548 unmask_evtchn(dev->evtchn);
550 printk("************************** FBFRONT\n");
552 return dev;
554 error:
555 free(err);
556 free_fbfront(dev);
557 return NULL;
558 }
560 static void fbfront_out_event(struct fbfront_dev *dev, union xenfb_out_event *event)
561 {
562 struct xenfb_page *page = dev->page;
563 uint32_t prod;
564 DEFINE_WAIT(w);
566 add_waiter(w, fbfront_queue);
567 while (page->out_prod - page->out_cons == XENFB_OUT_RING_LEN)
568 schedule();
569 remove_waiter(w);
571 prod = page->out_prod;
572 mb(); /* ensure ring space available */
573 XENFB_OUT_RING_REF(page, prod) = *event;
574 wmb(); /* ensure ring contents visible */
575 page->out_prod = prod + 1;
576 notify_remote_via_evtchn(dev->evtchn);
577 }
579 void fbfront_update(struct fbfront_dev *dev, int x, int y, int width, int height)
580 {
581 struct xenfb_update update;
583 if (dev->request_update <= 0)
584 return;
586 if (x < 0) {
587 width += x;
588 x = 0;
589 }
590 if (x + width > dev->width)
591 width = dev->width - x;
593 if (y < 0) {
594 height += y;
595 y = 0;
596 }
597 if (y + height > dev->height)
598 height = dev->height - y;
600 if (width <= 0 || height <= 0)
601 return;
603 update.type = XENFB_TYPE_UPDATE;
604 update.x = x;
605 update.y = y;
606 update.width = width;
607 update.height = height;
608 fbfront_out_event(dev, (union xenfb_out_event *) &update);
609 }
611 void fbfront_resize(struct fbfront_dev *dev, int width, int height, int stride, int depth, int offset)
612 {
613 struct xenfb_resize resize;
615 resize.type = XENFB_TYPE_RESIZE;
616 dev->width = resize.width = width;
617 dev->height = resize.height = height;
618 dev->stride = resize.stride = stride;
619 dev->depth = resize.depth = depth;
620 dev->offset = resize.offset = offset;
621 fbfront_out_event(dev, (union xenfb_out_event *) &resize);
622 }
624 void shutdown_fbfront(struct fbfront_dev *dev)
625 {
626 char* err = NULL;
627 XenbusState state;
629 char path[strlen(dev->backend) + 1 + 5 + 1];
630 char nodename[strlen(dev->nodename) + 1 + 5 + 1];
632 printk("close fb: backend at %s\n",dev->backend);
634 snprintf(path, sizeof(path), "%s/state", dev->backend);
635 snprintf(nodename, sizeof(nodename), "%s/state", dev->nodename);
636 if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosing)) != NULL) {
637 printk("shutdown_fbfront: error changing state to %d: %s\n",
638 XenbusStateClosing, err);
639 goto close_fbfront;
640 }
641 state = xenbus_read_integer(path);
642 while (err == NULL && state < XenbusStateClosing)
643 err = xenbus_wait_for_state_change(path, &state, &dev->events);
644 if (err) free(err);
646 if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosed)) != NULL) {
647 printk("shutdown_fbfront: error changing state to %d: %s\n",
648 XenbusStateClosed, err);
649 goto close_fbfront;
650 }
651 state = xenbus_read_integer(path);
652 if (state < XenbusStateClosed) {
653 xenbus_wait_for_state_change(path, &state, &dev->events);
654 if (err) free(err);
655 }
657 if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateInitialising)) != NULL) {
658 printk("shutdown_fbfront: error changing state to %d: %s\n",
659 XenbusStateInitialising, err);
660 goto close_fbfront;
661 }
662 // does not work yet
663 //xenbus_wait_for_value(path, "2", &dev->events);
665 close_fbfront:
666 if (err) free(err);
667 xenbus_unwatch_path_token(XBT_NIL, path, path);
669 snprintf(path, sizeof(path), "%s/page-ref", nodename);
670 xenbus_rm(XBT_NIL, path);
671 snprintf(path, sizeof(path), "%s/event-channel", nodename);
672 xenbus_rm(XBT_NIL, path);
673 snprintf(path, sizeof(path), "%s/protocol", nodename);
674 xenbus_rm(XBT_NIL, path);
675 snprintf(path, sizeof(path), "%s/feature-update", nodename);
676 xenbus_rm(XBT_NIL, path);
678 free_fbfront(dev);
679 }
681 #ifdef HAVE_LIBC
682 int fbfront_open(struct fbfront_dev *dev)
683 {
684 dev->fd = alloc_fd(FTYPE_FB);
685 printk("fb_open(%s) -> %d\n", dev->nodename, dev->fd);
686 files[dev->fd].fb.dev = dev;
687 return dev->fd;
688 }
689 #endif