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