xref: /openbmc/qemu/hw/display/xenfb.c (revision 5242ef88)
1 /*
2  *  xen paravirt framebuffer backend
3  *
4  *  Copyright IBM, Corp. 2005-2006
5  *  Copyright Red Hat, Inc. 2006-2008
6  *
7  *  Authors:
8  *       Anthony Liguori <aliguori@us.ibm.com>,
9  *       Markus Armbruster <armbru@redhat.com>,
10  *       Daniel P. Berrange <berrange@redhat.com>,
11  *       Pat Campbell <plc@novell.com>,
12  *       Gerd Hoffmann <kraxel@redhat.com>
13  *
14  *  This program is free software; you can redistribute it and/or modify
15  *  it under the terms of the GNU General Public License as published by
16  *  the Free Software Foundation; under version 2 of the License.
17  *
18  *  This program is distributed in the hope that it will be useful,
19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  *  GNU General Public License for more details.
22  *
23  *  You should have received a copy of the GNU General Public License along
24  *  with this program; if not, see <http://www.gnu.org/licenses/>.
25  */
26 
27 #include "qemu/osdep.h"
28 #include "qemu/units.h"
29 
30 #include "ui/input.h"
31 #include "ui/console.h"
32 #include "hw/xen/xen-legacy-backend.h"
33 
34 #include "hw/xen/interface/io/fbif.h"
35 #include "hw/xen/interface/io/kbdif.h"
36 #include "hw/xen/interface/io/protocols.h"
37 
38 #include "trace.h"
39 
40 #ifndef BTN_LEFT
41 #define BTN_LEFT 0x110 /* from <linux/input.h> */
42 #endif
43 
44 /* -------------------------------------------------------------------- */
45 
46 struct common {
47     struct XenLegacyDevice  xendev;  /* must be first */
48     void              *page;
49 };
50 
51 struct XenInput {
52     struct common c;
53     int abs_pointer_wanted; /* Whether guest supports absolute pointer */
54     int raw_pointer_wanted; /* Whether guest supports raw (unscaled) pointer */
55     QemuInputHandlerState *qkbd;
56     QemuInputHandlerState *qmou;
57     int axis[INPUT_AXIS__MAX];
58     int wheel;
59 };
60 
61 #define UP_QUEUE 8
62 
63 struct XenFB {
64     struct common     c;
65     QemuConsole       *con;
66     size_t            fb_len;
67     int               row_stride;
68     int               depth;
69     int               width;
70     int               height;
71     int               offset;
72     void              *pixels;
73     int               fbpages;
74     int               feature_update;
75     int               bug_trigger;
76     int               do_resize;
77 
78     struct {
79 	int x,y,w,h;
80     } up_rects[UP_QUEUE];
81     int               up_count;
82     int               up_fullscreen;
83 };
84 static const GraphicHwOps xenfb_ops;
85 
86 /* -------------------------------------------------------------------- */
87 
88 static int common_bind(struct common *c)
89 {
90     uint64_t val;
91     xen_pfn_t mfn;
92 
93     if (xenstore_read_fe_uint64(&c->xendev, "page-ref", &val) == -1)
94         return -1;
95     mfn = (xen_pfn_t)val;
96     assert(val == mfn);
97 
98     if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1)
99         return -1;
100 
101     c->page = xenforeignmemory_map(xen_fmem, c->xendev.dom,
102                                    PROT_READ | PROT_WRITE, 1, &mfn, NULL);
103     if (c->page == NULL)
104         return -1;
105 
106     xen_be_bind_evtchn(&c->xendev);
107     xen_pv_printf(&c->xendev, 1,
108                   "ring mfn %"PRI_xen_pfn", remote-port %d, local-port %d\n",
109                   mfn, c->xendev.remote_port, c->xendev.local_port);
110 
111     return 0;
112 }
113 
114 static void common_unbind(struct common *c)
115 {
116     xen_pv_unbind_evtchn(&c->xendev);
117     if (c->page) {
118         xenforeignmemory_unmap(xen_fmem, c->page, 1);
119 	c->page = NULL;
120     }
121 }
122 
123 /* -------------------------------------------------------------------- */
124 /* Send an event to the keyboard frontend driver */
125 static int xenfb_kbd_event(struct XenInput *xenfb,
126 			   union xenkbd_in_event *event)
127 {
128     struct xenkbd_page *page = xenfb->c.page;
129     uint32_t prod;
130 
131     if (xenfb->c.xendev.be_state != XenbusStateConnected)
132 	return 0;
133     if (!page)
134         return 0;
135 
136     prod = page->in_prod;
137     if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
138 	errno = EAGAIN;
139 	return -1;
140     }
141 
142     xen_mb();		/* ensure ring space available */
143     XENKBD_IN_RING_REF(page, prod) = *event;
144     xen_wmb();		/* ensure ring contents visible */
145     page->in_prod = prod + 1;
146     return xen_pv_send_notify(&xenfb->c.xendev);
147 }
148 
149 /* Send a keyboard (or mouse button) event */
150 static int xenfb_send_key(struct XenInput *xenfb, bool down, int keycode)
151 {
152     union xenkbd_in_event event;
153 
154     memset(&event, 0, XENKBD_IN_EVENT_SIZE);
155     event.type = XENKBD_TYPE_KEY;
156     event.key.pressed = down ? 1 : 0;
157     event.key.keycode = keycode;
158 
159     return xenfb_kbd_event(xenfb, &event);
160 }
161 
162 /* Send a relative mouse movement event */
163 static int xenfb_send_motion(struct XenInput *xenfb,
164 			     int rel_x, int rel_y, int rel_z)
165 {
166     union xenkbd_in_event event;
167 
168     memset(&event, 0, XENKBD_IN_EVENT_SIZE);
169     event.type = XENKBD_TYPE_MOTION;
170     event.motion.rel_x = rel_x;
171     event.motion.rel_y = rel_y;
172     event.motion.rel_z = rel_z;
173 
174     return xenfb_kbd_event(xenfb, &event);
175 }
176 
177 /* Send an absolute mouse movement event */
178 static int xenfb_send_position(struct XenInput *xenfb,
179 			       int abs_x, int abs_y, int z)
180 {
181     union xenkbd_in_event event;
182 
183     memset(&event, 0, XENKBD_IN_EVENT_SIZE);
184     event.type = XENKBD_TYPE_POS;
185     event.pos.abs_x = abs_x;
186     event.pos.abs_y = abs_y;
187     event.pos.rel_z = z;
188 
189     return xenfb_kbd_event(xenfb, &event);
190 }
191 
192 /*
193  * Send a key event from the client to the guest OS
194  * QEMU gives us a QCode.
195  * We have to turn this into a Linux Input layer keycode.
196  *
197  * Wish we could just send scancodes straight to the guest which
198  * already has code for dealing with this...
199  */
200 static void xenfb_key_event(DeviceState *dev, QemuConsole *src,
201                             InputEvent *evt)
202 {
203     struct XenInput *xenfb = (struct XenInput *)dev;
204     InputKeyEvent *key = evt->u.key.data;
205     int qcode = qemu_input_key_value_to_qcode(key->key);
206     int lnx;
207 
208     if (qcode < qemu_input_map_qcode_to_linux_len) {
209         lnx = qemu_input_map_qcode_to_linux[qcode];
210 
211         if (lnx) {
212             trace_xenfb_key_event(xenfb, lnx, key->down);
213             xenfb_send_key(xenfb, key->down, lnx);
214         }
215     }
216 }
217 
218 /*
219  * Send a mouse event from the client to the guest OS
220  *
221  * The QEMU mouse can be in either relative, or absolute mode.
222  * Movement is sent separately from button state, which has to
223  * be encoded as virtual key events. We also don't actually get
224  * given any button up/down events, so have to track changes in
225  * the button state.
226  */
227 static void xenfb_mouse_event(DeviceState *dev, QemuConsole *src,
228                               InputEvent *evt)
229 {
230     struct XenInput *xenfb = (struct XenInput *)dev;
231     InputBtnEvent *btn;
232     InputMoveEvent *move;
233     QemuConsole *con;
234     DisplaySurface *surface;
235     int scale;
236 
237     switch (evt->type) {
238     case INPUT_EVENT_KIND_BTN:
239         btn = evt->u.btn.data;
240         switch (btn->button) {
241         case INPUT_BUTTON_LEFT:
242             xenfb_send_key(xenfb, btn->down, BTN_LEFT);
243             break;
244         case INPUT_BUTTON_RIGHT:
245             xenfb_send_key(xenfb, btn->down, BTN_LEFT + 1);
246             break;
247         case INPUT_BUTTON_MIDDLE:
248             xenfb_send_key(xenfb, btn->down, BTN_LEFT + 2);
249             break;
250         case INPUT_BUTTON_WHEEL_UP:
251             if (btn->down) {
252                 xenfb->wheel--;
253             }
254             break;
255         case INPUT_BUTTON_WHEEL_DOWN:
256             if (btn->down) {
257                 xenfb->wheel++;
258             }
259             break;
260         default:
261             break;
262         }
263         break;
264 
265     case INPUT_EVENT_KIND_ABS:
266         move = evt->u.abs.data;
267         if (xenfb->raw_pointer_wanted) {
268             xenfb->axis[move->axis] = move->value;
269         } else {
270             con = qemu_console_lookup_by_index(0);
271             if (!con) {
272                 xen_pv_printf(&xenfb->c.xendev, 0, "No QEMU console available");
273                 return;
274             }
275             surface = qemu_console_surface(con);
276             switch (move->axis) {
277             case INPUT_AXIS_X:
278                 scale = surface_width(surface) - 1;
279                 break;
280             case INPUT_AXIS_Y:
281                 scale = surface_height(surface) - 1;
282                 break;
283             default:
284                 scale = 0x8000;
285                 break;
286             }
287             xenfb->axis[move->axis] = move->value * scale / 0x7fff;
288         }
289         break;
290 
291     case INPUT_EVENT_KIND_REL:
292         move = evt->u.rel.data;
293         xenfb->axis[move->axis] += move->value;
294         break;
295 
296     default:
297         break;
298     }
299 }
300 
301 static void xenfb_mouse_sync(DeviceState *dev)
302 {
303     struct XenInput *xenfb = (struct XenInput *)dev;
304 
305     trace_xenfb_mouse_event(xenfb, xenfb->axis[INPUT_AXIS_X],
306                             xenfb->axis[INPUT_AXIS_Y],
307                             xenfb->wheel, 0,
308                             xenfb->abs_pointer_wanted);
309     if (xenfb->abs_pointer_wanted) {
310         xenfb_send_position(xenfb, xenfb->axis[INPUT_AXIS_X],
311                             xenfb->axis[INPUT_AXIS_Y],
312                             xenfb->wheel);
313     } else {
314         xenfb_send_motion(xenfb, xenfb->axis[INPUT_AXIS_X],
315                           xenfb->axis[INPUT_AXIS_Y],
316                           xenfb->wheel);
317         xenfb->axis[INPUT_AXIS_X] = 0;
318         xenfb->axis[INPUT_AXIS_Y] = 0;
319     }
320     xenfb->wheel = 0;
321 }
322 
323 static QemuInputHandler xenfb_keyboard = {
324     .name  = "Xen PV Keyboard",
325     .mask  = INPUT_EVENT_MASK_KEY,
326     .event = xenfb_key_event,
327 };
328 
329 static QemuInputHandler xenfb_abs_mouse = {
330     .name  = "Xen PV Mouse",
331     .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
332     .event = xenfb_mouse_event,
333     .sync  = xenfb_mouse_sync,
334 };
335 
336 static QemuInputHandler xenfb_rel_mouse = {
337     .name  = "Xen PV Mouse",
338     .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
339     .event = xenfb_mouse_event,
340     .sync  = xenfb_mouse_sync,
341 };
342 
343 static int input_init(struct XenLegacyDevice *xendev)
344 {
345     xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
346     xenstore_write_be_int(xendev, "feature-raw-pointer", 1);
347     return 0;
348 }
349 
350 static int input_initialise(struct XenLegacyDevice *xendev)
351 {
352     struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
353     int rc;
354 
355     rc = common_bind(&in->c);
356     if (rc != 0)
357 	return rc;
358 
359     return 0;
360 }
361 
362 static void input_connected(struct XenLegacyDevice *xendev)
363 {
364     struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
365 
366     if (xenstore_read_fe_int(xendev, "request-abs-pointer",
367                              &in->abs_pointer_wanted) == -1) {
368         in->abs_pointer_wanted = 0;
369     }
370     if (xenstore_read_fe_int(xendev, "request-raw-pointer",
371                              &in->raw_pointer_wanted) == -1) {
372         in->raw_pointer_wanted = 0;
373     }
374     if (in->raw_pointer_wanted && in->abs_pointer_wanted == 0) {
375         xen_pv_printf(xendev, 0, "raw pointer set without abs pointer");
376     }
377 
378     if (in->qkbd) {
379         qemu_input_handler_unregister(in->qkbd);
380     }
381     if (in->qmou) {
382         qemu_input_handler_unregister(in->qmou);
383     }
384     trace_xenfb_input_connected(xendev, in->abs_pointer_wanted);
385 
386     in->qkbd = qemu_input_handler_register((DeviceState *)in, &xenfb_keyboard);
387     in->qmou = qemu_input_handler_register((DeviceState *)in,
388                in->abs_pointer_wanted ? &xenfb_abs_mouse : &xenfb_rel_mouse);
389 
390     if (in->raw_pointer_wanted) {
391         qemu_input_handler_activate(in->qkbd);
392         qemu_input_handler_activate(in->qmou);
393     }
394 }
395 
396 static void input_disconnect(struct XenLegacyDevice *xendev)
397 {
398     struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
399 
400     if (in->qkbd) {
401         qemu_input_handler_unregister(in->qkbd);
402         in->qkbd = NULL;
403     }
404     if (in->qmou) {
405         qemu_input_handler_unregister(in->qmou);
406         in->qmou = NULL;
407     }
408     common_unbind(&in->c);
409 }
410 
411 static void input_event(struct XenLegacyDevice *xendev)
412 {
413     struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
414     struct xenkbd_page *page = xenfb->c.page;
415 
416     /* We don't understand any keyboard events, so just ignore them. */
417     if (page->out_prod == page->out_cons)
418 	return;
419     page->out_cons = page->out_prod;
420     xen_pv_send_notify(&xenfb->c.xendev);
421 }
422 
423 /* -------------------------------------------------------------------- */
424 
425 static void xenfb_copy_mfns(int mode, int count, xen_pfn_t *dst, void *src)
426 {
427     uint32_t *src32 = src;
428     uint64_t *src64 = src;
429     int i;
430 
431     for (i = 0; i < count; i++)
432 	dst[i] = (mode == 32) ? src32[i] : src64[i];
433 }
434 
435 static int xenfb_map_fb(struct XenFB *xenfb)
436 {
437     struct xenfb_page *page = xenfb->c.page;
438     char *protocol = xenfb->c.xendev.protocol;
439     int n_fbdirs;
440     xen_pfn_t *pgmfns = NULL;
441     xen_pfn_t *fbmfns = NULL;
442     void *map, *pd;
443     int mode, ret = -1;
444 
445     /* default to native */
446     pd = page->pd;
447     mode = sizeof(unsigned long) * 8;
448 
449     if (!protocol) {
450 	/*
451 	 * Undefined protocol, some guesswork needed.
452 	 *
453 	 * Old frontends which don't set the protocol use
454 	 * one page directory only, thus pd[1] must be zero.
455 	 * pd[1] of the 32bit struct layout and the lower
456 	 * 32 bits of pd[0] of the 64bit struct layout have
457 	 * the same location, so we can check that ...
458 	 */
459 	uint32_t *ptr32 = NULL;
460 	uint32_t *ptr64 = NULL;
461 #if defined(__i386__)
462 	ptr32 = (void*)page->pd;
463 	ptr64 = ((void*)page->pd) + 4;
464 #elif defined(__x86_64__)
465 	ptr32 = ((void*)page->pd) - 4;
466 	ptr64 = (void*)page->pd;
467 #endif
468 	if (ptr32) {
469 	    if (ptr32[1] == 0) {
470 		mode = 32;
471 		pd   = ptr32;
472 	    } else {
473 		mode = 64;
474 		pd   = ptr64;
475 	    }
476 	}
477 #if defined(__x86_64__)
478     } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
479 	/* 64bit dom0, 32bit domU */
480 	mode = 32;
481 	pd   = ((void*)page->pd) - 4;
482 #elif defined(__i386__)
483     } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
484 	/* 32bit dom0, 64bit domU */
485 	mode = 64;
486 	pd   = ((void*)page->pd) + 4;
487 #endif
488     }
489 
490     if (xenfb->pixels) {
491         munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
492         xenfb->pixels = NULL;
493     }
494 
495     xenfb->fbpages = DIV_ROUND_UP(xenfb->fb_len, XC_PAGE_SIZE);
496     n_fbdirs = xenfb->fbpages * mode / 8;
497     n_fbdirs = DIV_ROUND_UP(n_fbdirs, XC_PAGE_SIZE);
498 
499     pgmfns = g_new0(xen_pfn_t, n_fbdirs);
500     fbmfns = g_new0(xen_pfn_t, xenfb->fbpages);
501 
502     xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
503     map = xenforeignmemory_map(xen_fmem, xenfb->c.xendev.dom,
504                                PROT_READ, n_fbdirs, pgmfns, NULL);
505     if (map == NULL)
506 	goto out;
507     xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
508     xenforeignmemory_unmap(xen_fmem, map, n_fbdirs);
509 
510     xenfb->pixels = xenforeignmemory_map(xen_fmem, xenfb->c.xendev.dom,
511             PROT_READ, xenfb->fbpages, fbmfns, NULL);
512     if (xenfb->pixels == NULL)
513 	goto out;
514 
515     ret = 0; /* all is fine */
516 
517 out:
518     g_free(pgmfns);
519     g_free(fbmfns);
520     return ret;
521 }
522 
523 static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim,
524                               int width, int height, int depth,
525                               size_t fb_len, int offset, int row_stride)
526 {
527     size_t mfn_sz = sizeof_field(struct xenfb_page, pd[0]);
528     size_t pd_len = sizeof_field(struct xenfb_page, pd) / mfn_sz;
529     size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
530     size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
531     int max_width, max_height;
532 
533     if (fb_len_lim > fb_len_max) {
534         xen_pv_printf(&xenfb->c.xendev, 0,
535                       "fb size limit %zu exceeds %zu, corrected\n",
536                       fb_len_lim, fb_len_max);
537         fb_len_lim = fb_len_max;
538     }
539     if (fb_len_lim && fb_len > fb_len_lim) {
540         xen_pv_printf(&xenfb->c.xendev, 0,
541                       "frontend fb size %zu limited to %zu\n",
542                       fb_len, fb_len_lim);
543         fb_len = fb_len_lim;
544     }
545     if (depth != 8 && depth != 16 && depth != 24 && depth != 32) {
546         xen_pv_printf(&xenfb->c.xendev, 0,
547                       "can't handle frontend fb depth %d\n",
548                       depth);
549         return -1;
550     }
551     if (row_stride <= 0 || row_stride > fb_len) {
552         xen_pv_printf(&xenfb->c.xendev, 0, "invalid frontend stride %d\n",
553                       row_stride);
554         return -1;
555     }
556     max_width = row_stride / (depth / 8);
557     if (width < 0 || width > max_width) {
558         xen_pv_printf(&xenfb->c.xendev, 0,
559                       "invalid frontend width %d limited to %d\n",
560                       width, max_width);
561         width = max_width;
562     }
563     if (offset < 0 || offset >= fb_len) {
564         xen_pv_printf(&xenfb->c.xendev, 0,
565                       "invalid frontend offset %d (max %zu)\n",
566                       offset, fb_len - 1);
567         return -1;
568     }
569     max_height = (fb_len - offset) / row_stride;
570     if (height < 0 || height > max_height) {
571         xen_pv_printf(&xenfb->c.xendev, 0,
572                       "invalid frontend height %d limited to %d\n",
573                       height, max_height);
574         height = max_height;
575     }
576     xenfb->fb_len = fb_len;
577     xenfb->row_stride = row_stride;
578     xenfb->depth = depth;
579     xenfb->width = width;
580     xenfb->height = height;
581     xenfb->offset = offset;
582     xenfb->up_fullscreen = 1;
583     xenfb->do_resize = 1;
584     xen_pv_printf(&xenfb->c.xendev, 1,
585                   "framebuffer %dx%dx%d offset %d stride %d\n",
586                   width, height, depth, offset, row_stride);
587     return 0;
588 }
589 
590 /* A convenient function for munging pixels between different depths */
591 #define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB)                        \
592     for (line = y ; line < (y+h) ; line++) {				\
593 	SRC_T *src = (SRC_T *)(xenfb->pixels				\
594 			       + xenfb->offset				\
595 			       + (line * xenfb->row_stride)		\
596 			       + (x * xenfb->depth / 8));		\
597 	DST_T *dst = (DST_T *)(data					\
598 			       + (line * linesize)			\
599 			       + (x * bpp / 8));			\
600 	int col;							\
601 	const int RSS = 32 - (RSB + GSB + BSB);				\
602 	const int GSS = 32 - (GSB + BSB);				\
603 	const int BSS = 32 - (BSB);					\
604 	const uint32_t RSM = (~0U) << (32 - RSB);			\
605 	const uint32_t GSM = (~0U) << (32 - GSB);			\
606 	const uint32_t BSM = (~0U) << (32 - BSB);			\
607 	const int RDS = 32 - (RDB + GDB + BDB);				\
608 	const int GDS = 32 - (GDB + BDB);				\
609 	const int BDS = 32 - (BDB);					\
610 	const uint32_t RDM = (~0U) << (32 - RDB);			\
611 	const uint32_t GDM = (~0U) << (32 - GDB);			\
612 	const uint32_t BDM = (~0U) << (32 - BDB);			\
613 	for (col = x ; col < (x+w) ; col++) {				\
614 	    uint32_t spix = *src;					\
615 	    *dst = (((spix << RSS) & RSM & RDM) >> RDS) |		\
616 		(((spix << GSS) & GSM & GDM) >> GDS) |			\
617 		(((spix << BSS) & BSM & BDM) >> BDS);			\
618 	    src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8);	\
619 	    dst = (DST_T *) ((unsigned long) dst + bpp / 8);		\
620 	}								\
621     }
622 
623 
624 /*
625  * This copies data from the guest framebuffer region, into QEMU's
626  * displaysurface. qemu uses 16 or 32 bpp.  In case the pv framebuffer
627  * uses something else we must convert and copy, otherwise we can
628  * supply the buffer directly and no thing here.
629  */
630 static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
631 {
632     DisplaySurface *surface = qemu_console_surface(xenfb->con);
633     int line, oops = 0;
634     int bpp = surface_bits_per_pixel(surface);
635     int linesize = surface_stride(surface);
636     uint8_t *data = surface_data(surface);
637 
638     if (!is_buffer_shared(surface)) {
639         switch (xenfb->depth) {
640         case 8:
641             if (bpp == 16) {
642                 BLT(uint8_t, uint16_t,   3, 3, 2,   5, 6, 5);
643             } else if (bpp == 32) {
644                 BLT(uint8_t, uint32_t,   3, 3, 2,   8, 8, 8);
645             } else {
646                 oops = 1;
647             }
648             break;
649         case 24:
650             if (bpp == 16) {
651                 BLT(uint32_t, uint16_t,  8, 8, 8,   5, 6, 5);
652             } else if (bpp == 32) {
653                 BLT(uint32_t, uint32_t,  8, 8, 8,   8, 8, 8);
654             } else {
655                 oops = 1;
656             }
657             break;
658         default:
659             oops = 1;
660 	}
661     }
662     if (oops) /* should not happen */
663         xen_pv_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
664                       __func__, xenfb->depth, bpp);
665 
666     dpy_gfx_update(xenfb->con, x, y, w, h);
667 }
668 
669 #ifdef XENFB_TYPE_REFRESH_PERIOD
670 static int xenfb_queue_full(struct XenFB *xenfb)
671 {
672     struct xenfb_page *page = xenfb->c.page;
673     uint32_t cons, prod;
674 
675     if (!page)
676         return 1;
677 
678     prod = page->in_prod;
679     cons = page->in_cons;
680     return prod - cons == XENFB_IN_RING_LEN;
681 }
682 
683 static void xenfb_send_event(struct XenFB *xenfb, union xenfb_in_event *event)
684 {
685     uint32_t prod;
686     struct xenfb_page *page = xenfb->c.page;
687 
688     prod = page->in_prod;
689     /* caller ensures !xenfb_queue_full() */
690     xen_mb();                   /* ensure ring space available */
691     XENFB_IN_RING_REF(page, prod) = *event;
692     xen_wmb();                  /* ensure ring contents visible */
693     page->in_prod = prod + 1;
694 
695     xen_pv_send_notify(&xenfb->c.xendev);
696 }
697 
698 static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
699 {
700     union xenfb_in_event event;
701 
702     memset(&event, 0, sizeof(event));
703     event.type = XENFB_TYPE_REFRESH_PERIOD;
704     event.refresh_period.period = period;
705     xenfb_send_event(xenfb, &event);
706 }
707 #endif
708 
709 /*
710  * Periodic update of display.
711  * Also transmit the refresh interval to the frontend.
712  *
713  * Never ever do any qemu display operations
714  * (resize, screen update) outside this function.
715  * Our screen might be inactive.  When asked for
716  * an update we know it is active.
717  */
718 static void xenfb_update(void *opaque)
719 {
720     struct XenFB *xenfb = opaque;
721     DisplaySurface *surface;
722     int i;
723 
724     if (xenfb->c.xendev.be_state != XenbusStateConnected)
725         return;
726 
727     if (!xenfb->feature_update) {
728         /* we don't get update notifications, thus use the
729          * sledge hammer approach ... */
730         xenfb->up_fullscreen = 1;
731     }
732 
733     /* resize if needed */
734     if (xenfb->do_resize) {
735         pixman_format_code_t format;
736 
737         xenfb->do_resize = 0;
738         switch (xenfb->depth) {
739         case 16:
740         case 32:
741             /* console.c supported depth -> buffer can be used directly */
742             format = qemu_default_pixman_format(xenfb->depth, true);
743             surface = qemu_create_displaysurface_from
744                 (xenfb->width, xenfb->height, format,
745                  xenfb->row_stride, xenfb->pixels + xenfb->offset);
746             break;
747         default:
748             /* we must convert stuff */
749             surface = qemu_create_displaysurface(xenfb->width, xenfb->height);
750             break;
751         }
752         dpy_gfx_replace_surface(xenfb->con, surface);
753         xen_pv_printf(&xenfb->c.xendev, 1,
754                       "update: resizing: %dx%d @ %d bpp%s\n",
755                       xenfb->width, xenfb->height, xenfb->depth,
756                       is_buffer_shared(surface) ? " (shared)" : "");
757         xenfb->up_fullscreen = 1;
758     }
759 
760     /* run queued updates */
761     if (xenfb->up_fullscreen) {
762         xen_pv_printf(&xenfb->c.xendev, 3, "update: fullscreen\n");
763         xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
764     } else if (xenfb->up_count) {
765         xen_pv_printf(&xenfb->c.xendev, 3, "update: %d rects\n",
766                       xenfb->up_count);
767         for (i = 0; i < xenfb->up_count; i++)
768             xenfb_guest_copy(xenfb,
769                              xenfb->up_rects[i].x,
770                              xenfb->up_rects[i].y,
771                              xenfb->up_rects[i].w,
772                              xenfb->up_rects[i].h);
773     } else {
774         xen_pv_printf(&xenfb->c.xendev, 3, "update: nothing\n");
775     }
776     xenfb->up_count = 0;
777     xenfb->up_fullscreen = 0;
778 }
779 
780 static void xenfb_update_interval(void *opaque, uint64_t interval)
781 {
782     struct XenFB *xenfb = opaque;
783 
784     if (xenfb->feature_update) {
785 #ifdef XENFB_TYPE_REFRESH_PERIOD
786         if (xenfb_queue_full(xenfb)) {
787             return;
788         }
789         xenfb_send_refresh_period(xenfb, interval);
790 #endif
791     }
792 }
793 
794 /* QEMU display state changed, so refresh the framebuffer copy */
795 static void xenfb_invalidate(void *opaque)
796 {
797     struct XenFB *xenfb = opaque;
798     xenfb->up_fullscreen = 1;
799 }
800 
801 static void xenfb_handle_events(struct XenFB *xenfb)
802 {
803     uint32_t prod, cons, out_cons;
804     struct xenfb_page *page = xenfb->c.page;
805 
806     prod = page->out_prod;
807     out_cons = page->out_cons;
808     if (prod - out_cons > XENFB_OUT_RING_LEN) {
809         return;
810     }
811     xen_rmb();		/* ensure we see ring contents up to prod */
812     for (cons = out_cons; cons != prod; cons++) {
813 	union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
814         uint8_t type = event->type;
815 	int x, y, w, h;
816 
817 	switch (type) {
818 	case XENFB_TYPE_UPDATE:
819 	    if (xenfb->up_count == UP_QUEUE)
820 		xenfb->up_fullscreen = 1;
821 	    if (xenfb->up_fullscreen)
822 		break;
823 	    x = MAX(event->update.x, 0);
824 	    y = MAX(event->update.y, 0);
825 	    w = MIN(event->update.width, xenfb->width - x);
826 	    h = MIN(event->update.height, xenfb->height - y);
827 	    if (w < 0 || h < 0) {
828                 xen_pv_printf(&xenfb->c.xendev, 1, "bogus update ignored\n");
829 		break;
830 	    }
831 	    if (x != event->update.x ||
832                 y != event->update.y ||
833 		w != event->update.width ||
834 		h != event->update.height) {
835                 xen_pv_printf(&xenfb->c.xendev, 1, "bogus update clipped\n");
836 	    }
837 	    if (w == xenfb->width && h > xenfb->height / 2) {
838 		/* scroll detector: updated more than 50% of the lines,
839 		 * don't bother keeping track of the rectangles then */
840 		xenfb->up_fullscreen = 1;
841 	    } else {
842 		xenfb->up_rects[xenfb->up_count].x = x;
843 		xenfb->up_rects[xenfb->up_count].y = y;
844 		xenfb->up_rects[xenfb->up_count].w = w;
845 		xenfb->up_rects[xenfb->up_count].h = h;
846 		xenfb->up_count++;
847 	    }
848 	    break;
849 #ifdef XENFB_TYPE_RESIZE
850 	case XENFB_TYPE_RESIZE:
851 	    if (xenfb_configure_fb(xenfb, xenfb->fb_len,
852 				   event->resize.width,
853 				   event->resize.height,
854 				   event->resize.depth,
855 				   xenfb->fb_len,
856 				   event->resize.offset,
857 				   event->resize.stride) < 0)
858 		break;
859 	    xenfb_invalidate(xenfb);
860 	    break;
861 #endif
862 	}
863     }
864     xen_mb();		/* ensure we're done with ring contents */
865     page->out_cons = cons;
866 }
867 
868 static int fb_init(struct XenLegacyDevice *xendev)
869 {
870 #ifdef XENFB_TYPE_RESIZE
871     xenstore_write_be_int(xendev, "feature-resize", 1);
872 #endif
873     return 0;
874 }
875 
876 static int fb_initialise(struct XenLegacyDevice *xendev)
877 {
878     struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
879     struct xenfb_page *fb_page;
880     int videoram;
881     int rc;
882 
883     if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1)
884 	videoram = 0;
885 
886     rc = common_bind(&fb->c);
887     if (rc != 0)
888 	return rc;
889 
890     fb_page = fb->c.page;
891     rc = xenfb_configure_fb(fb, videoram * MiB,
892 			    fb_page->width, fb_page->height, fb_page->depth,
893 			    fb_page->mem_length, 0, fb_page->line_length);
894     if (rc != 0)
895 	return rc;
896 
897     rc = xenfb_map_fb(fb);
898     if (rc != 0)
899 	return rc;
900 
901     fb->con = graphic_console_init(NULL, 0, &xenfb_ops, fb);
902 
903     if (xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update) == -1)
904 	fb->feature_update = 0;
905     if (fb->feature_update)
906 	xenstore_write_be_int(xendev, "request-update", 1);
907 
908     xen_pv_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
909 		  fb->feature_update, videoram);
910     return 0;
911 }
912 
913 static void fb_disconnect(struct XenLegacyDevice *xendev)
914 {
915     struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
916 
917     /*
918      * FIXME: qemu can't un-init gfx display (yet?).
919      *   Replacing the framebuffer with anonymous shared memory
920      *   instead.  This releases the guest pages and keeps qemu happy.
921      */
922     xenforeignmemory_unmap(xen_fmem, fb->pixels, fb->fbpages);
923     fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
924                       PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
925                       -1, 0);
926     if (fb->pixels == MAP_FAILED) {
927         xen_pv_printf(xendev, 0,
928                 "Couldn't replace the framebuffer with anonymous memory errno=%d\n",
929                 errno);
930     }
931     common_unbind(&fb->c);
932     fb->feature_update = 0;
933     fb->bug_trigger    = 0;
934 }
935 
936 static void fb_frontend_changed(struct XenLegacyDevice *xendev,
937                                 const char *node)
938 {
939     struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
940 
941     /*
942      * Set state to Connected *again* once the frontend switched
943      * to connected.  We must trigger the watch a second time to
944      * workaround a frontend bug.
945      */
946     if (fb->bug_trigger == 0 && strcmp(node, "state") == 0 &&
947         xendev->fe_state == XenbusStateConnected &&
948         xendev->be_state == XenbusStateConnected) {
949         xen_pv_printf(xendev, 2, "re-trigger connected (frontend bug)\n");
950         xen_be_set_state(xendev, XenbusStateConnected);
951         fb->bug_trigger = 1; /* only once */
952     }
953 }
954 
955 static void fb_event(struct XenLegacyDevice *xendev)
956 {
957     struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
958 
959     xenfb_handle_events(xenfb);
960     xen_pv_send_notify(&xenfb->c.xendev);
961 }
962 
963 /* -------------------------------------------------------------------- */
964 
965 struct XenDevOps xen_kbdmouse_ops = {
966     .size       = sizeof(struct XenInput),
967     .init       = input_init,
968     .initialise = input_initialise,
969     .connected  = input_connected,
970     .disconnect = input_disconnect,
971     .event      = input_event,
972 };
973 
974 struct XenDevOps xen_framebuffer_ops = {
975     .size       = sizeof(struct XenFB),
976     .init       = fb_init,
977     .initialise = fb_initialise,
978     .disconnect = fb_disconnect,
979     .event      = fb_event,
980     .frontend_changed = fb_frontend_changed,
981 };
982 
983 static const GraphicHwOps xenfb_ops = {
984     .invalidate  = xenfb_invalidate,
985     .gfx_update  = xenfb_update,
986     .update_interval = xenfb_update_interval,
987 };
988