]> Git Repo - qemu.git/blob - hw/display/xenfb.c
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
[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 "sysemu/char.h"
32 #include "hw/xen/xen_backend.h"
33
34 #include <xen/event_channel.h>
35 #include <xen/io/fbif.h>
36 #include <xen/io/kbdif.h>
37 #include <xen/io/protocols.h>
38
39 #include "trace.h"
40
41 #ifndef BTN_LEFT
42 #define BTN_LEFT 0x110 /* from <linux/input.h> */
43 #endif
44
45 /* -------------------------------------------------------------------- */
46
47 struct common {
48     struct XenDevice  xendev;  /* must be first */
49     void              *page;
50     QemuConsole       *con;
51 };
52
53 struct XenInput {
54     struct common c;
55     int abs_pointer_wanted; /* Whether guest supports absolute pointer */
56     int button_state;       /* Last seen pointer button state */
57     int extended;
58     QEMUPutMouseEntry *qmouse;
59 };
60
61 #define UP_QUEUE 8
62
63 struct XenFB {
64     struct common     c;
65     size_t            fb_len;
66     int               row_stride;
67     int               depth;
68     int               width;
69     int               height;
70     int               offset;
71     void              *pixels;
72     int               fbpages;
73     int               feature_update;
74     int               bug_trigger;
75     int               have_console;
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
85 /* -------------------------------------------------------------------- */
86
87 static int common_bind(struct common *c)
88 {
89     uint64_t val;
90     xen_pfn_t mfn;
91
92     if (xenstore_read_fe_uint64(&c->xendev, "page-ref", &val) == -1)
93         return -1;
94     mfn = (xen_pfn_t)val;
95     assert(val == mfn);
96
97     if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1)
98         return -1;
99
100     c->page = xenforeignmemory_map(xen_fmem, c->xendev.dom,
101                                    PROT_READ | PROT_WRITE, 1, &mfn, NULL);
102     if (c->page == NULL)
103         return -1;
104
105     xen_be_bind_evtchn(&c->xendev);
106     xen_be_printf(&c->xendev, 1, "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_be_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_be_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     DisplaySurface *surface = qemu_console_surface(xenfb->c.con);
310     int dw = surface_width(surface);
311     int dh = surface_height(surface);
312     int i;
313
314     trace_xenfb_mouse_event(opaque, dx, dy, dz, button_state,
315                             xenfb->abs_pointer_wanted);
316     if (xenfb->abs_pointer_wanted)
317         xenfb_send_position(xenfb,
318                             dx * (dw - 1) / 0x7fff,
319                             dy * (dh - 1) / 0x7fff,
320                             dz);
321     else
322         xenfb_send_motion(xenfb, dx, dy, dz);
323
324     for (i = 0 ; i < 8 ; i++) {
325         int lastDown = xenfb->button_state & (1 << i);
326         int down = button_state & (1 << i);
327         if (down == lastDown)
328             continue;
329
330         if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
331             return;
332     }
333     xenfb->button_state = button_state;
334 }
335
336 static int input_init(struct XenDevice *xendev)
337 {
338     xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
339     return 0;
340 }
341
342 static int input_initialise(struct XenDevice *xendev)
343 {
344     struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
345     int rc;
346
347     if (!in->c.con) {
348         xen_be_printf(xendev, 1, "ds not set (yet)\n");
349         return -1;
350     }
351
352     rc = common_bind(&in->c);
353     if (rc != 0)
354         return rc;
355
356     qemu_add_kbd_event_handler(xenfb_key_event, in);
357     return 0;
358 }
359
360 static void input_connected(struct XenDevice *xendev)
361 {
362     struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
363
364     if (xenstore_read_fe_int(xendev, "request-abs-pointer",
365                              &in->abs_pointer_wanted) == -1) {
366         in->abs_pointer_wanted = 0;
367     }
368
369     if (in->qmouse) {
370         qemu_remove_mouse_event_handler(in->qmouse);
371     }
372     trace_xenfb_input_connected(xendev, in->abs_pointer_wanted);
373     in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
374                                               in->abs_pointer_wanted,
375                                               "Xen PVFB Mouse");
376 }
377
378 static void input_disconnect(struct XenDevice *xendev)
379 {
380     struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
381
382     if (in->qmouse) {
383         qemu_remove_mouse_event_handler(in->qmouse);
384         in->qmouse = NULL;
385     }
386     qemu_add_kbd_event_handler(NULL, NULL);
387     common_unbind(&in->c);
388 }
389
390 static void input_event(struct XenDevice *xendev)
391 {
392     struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
393     struct xenkbd_page *page = xenfb->c.page;
394
395     /* We don't understand any keyboard events, so just ignore them. */
396     if (page->out_prod == page->out_cons)
397         return;
398     page->out_cons = page->out_prod;
399     xen_be_send_notify(&xenfb->c.xendev);
400 }
401
402 /* -------------------------------------------------------------------- */
403
404 static void xenfb_copy_mfns(int mode, int count, xen_pfn_t *dst, void *src)
405 {
406     uint32_t *src32 = src;
407     uint64_t *src64 = src;
408     int i;
409
410     for (i = 0; i < count; i++)
411         dst[i] = (mode == 32) ? src32[i] : src64[i];
412 }
413
414 static int xenfb_map_fb(struct XenFB *xenfb)
415 {
416     struct xenfb_page *page = xenfb->c.page;
417     char *protocol = xenfb->c.xendev.protocol;
418     int n_fbdirs;
419     xen_pfn_t *pgmfns = NULL;
420     xen_pfn_t *fbmfns = NULL;
421     void *map, *pd;
422     int mode, ret = -1;
423
424     /* default to native */
425     pd = page->pd;
426     mode = sizeof(unsigned long) * 8;
427
428     if (!protocol) {
429         /*
430          * Undefined protocol, some guesswork needed.
431          *
432          * Old frontends which don't set the protocol use
433          * one page directory only, thus pd[1] must be zero.
434          * pd[1] of the 32bit struct layout and the lower
435          * 32 bits of pd[0] of the 64bit struct layout have
436          * the same location, so we can check that ...
437          */
438         uint32_t *ptr32 = NULL;
439         uint32_t *ptr64 = NULL;
440 #if defined(__i386__)
441         ptr32 = (void*)page->pd;
442         ptr64 = ((void*)page->pd) + 4;
443 #elif defined(__x86_64__)
444         ptr32 = ((void*)page->pd) - 4;
445         ptr64 = (void*)page->pd;
446 #endif
447         if (ptr32) {
448             if (ptr32[1] == 0) {
449                 mode = 32;
450                 pd   = ptr32;
451             } else {
452                 mode = 64;
453                 pd   = ptr64;
454             }
455         }
456 #if defined(__x86_64__)
457     } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
458         /* 64bit dom0, 32bit domU */
459         mode = 32;
460         pd   = ((void*)page->pd) - 4;
461 #elif defined(__i386__)
462     } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
463         /* 32bit dom0, 64bit domU */
464         mode = 64;
465         pd   = ((void*)page->pd) + 4;
466 #endif
467     }
468
469     if (xenfb->pixels) {
470         munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
471         xenfb->pixels = NULL;
472     }
473
474     xenfb->fbpages = DIV_ROUND_UP(xenfb->fb_len, XC_PAGE_SIZE);
475     n_fbdirs = xenfb->fbpages * mode / 8;
476     n_fbdirs = DIV_ROUND_UP(n_fbdirs, XC_PAGE_SIZE);
477
478     pgmfns = g_malloc0(sizeof(xen_pfn_t) * n_fbdirs);
479     fbmfns = g_malloc0(sizeof(xen_pfn_t) * xenfb->fbpages);
480
481     xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
482     map = xenforeignmemory_map(xen_fmem, xenfb->c.xendev.dom,
483                                PROT_READ, n_fbdirs, pgmfns, NULL);
484     if (map == NULL)
485         goto out;
486     xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
487     xenforeignmemory_unmap(xen_fmem, map, n_fbdirs);
488
489     xenfb->pixels = xenforeignmemory_map(xen_fmem, xenfb->c.xendev.dom,
490             PROT_READ, xenfb->fbpages, fbmfns, NULL);
491     if (xenfb->pixels == NULL)
492         goto out;
493
494     ret = 0; /* all is fine */
495
496 out:
497     g_free(pgmfns);
498     g_free(fbmfns);
499     return ret;
500 }
501
502 static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim,
503                               int width, int height, int depth,
504                               size_t fb_len, int offset, int row_stride)
505 {
506     size_t mfn_sz = sizeof(*((struct xenfb_page *)0)->pd);
507     size_t pd_len = sizeof(((struct xenfb_page *)0)->pd) / mfn_sz;
508     size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
509     size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
510     int max_width, max_height;
511
512     if (fb_len_lim > fb_len_max) {
513         xen_be_printf(&xenfb->c.xendev, 0, "fb size limit %zu exceeds %zu, corrected\n",
514                       fb_len_lim, fb_len_max);
515         fb_len_lim = fb_len_max;
516     }
517     if (fb_len_lim && fb_len > fb_len_lim) {
518         xen_be_printf(&xenfb->c.xendev, 0, "frontend fb size %zu limited to %zu\n",
519                       fb_len, fb_len_lim);
520         fb_len = fb_len_lim;
521     }
522     if (depth != 8 && depth != 16 && depth != 24 && depth != 32) {
523         xen_be_printf(&xenfb->c.xendev, 0, "can't handle frontend fb depth %d\n",
524                       depth);
525         return -1;
526     }
527     if (row_stride <= 0 || row_stride > fb_len) {
528         xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend stride %d\n", row_stride);
529         return -1;
530     }
531     max_width = row_stride / (depth / 8);
532     if (width < 0 || width > max_width) {
533         xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend width %d limited to %d\n",
534                       width, max_width);
535         width = max_width;
536     }
537     if (offset < 0 || offset >= fb_len) {
538         xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend offset %d (max %zu)\n",
539                       offset, fb_len - 1);
540         return -1;
541     }
542     max_height = (fb_len - offset) / row_stride;
543     if (height < 0 || height > max_height) {
544         xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend height %d limited to %d\n",
545                       height, max_height);
546         height = max_height;
547     }
548     xenfb->fb_len = fb_len;
549     xenfb->row_stride = row_stride;
550     xenfb->depth = depth;
551     xenfb->width = width;
552     xenfb->height = height;
553     xenfb->offset = offset;
554     xenfb->up_fullscreen = 1;
555     xenfb->do_resize = 1;
556     xen_be_printf(&xenfb->c.xendev, 1, "framebuffer %dx%dx%d offset %d stride %d\n",
557                   width, height, depth, offset, row_stride);
558     return 0;
559 }
560
561 /* A convenient function for munging pixels between different depths */
562 #define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB)                        \
563     for (line = y ; line < (y+h) ; line++) {                            \
564         SRC_T *src = (SRC_T *)(xenfb->pixels                            \
565                                + xenfb->offset                          \
566                                + (line * xenfb->row_stride)             \
567                                + (x * xenfb->depth / 8));               \
568         DST_T *dst = (DST_T *)(data                                     \
569                                + (line * linesize)                      \
570                                + (x * bpp / 8));                        \
571         int col;                                                        \
572         const int RSS = 32 - (RSB + GSB + BSB);                         \
573         const int GSS = 32 - (GSB + BSB);                               \
574         const int BSS = 32 - (BSB);                                     \
575         const uint32_t RSM = (~0U) << (32 - RSB);                       \
576         const uint32_t GSM = (~0U) << (32 - GSB);                       \
577         const uint32_t BSM = (~0U) << (32 - BSB);                       \
578         const int RDS = 32 - (RDB + GDB + BDB);                         \
579         const int GDS = 32 - (GDB + BDB);                               \
580         const int BDS = 32 - (BDB);                                     \
581         const uint32_t RDM = (~0U) << (32 - RDB);                       \
582         const uint32_t GDM = (~0U) << (32 - GDB);                       \
583         const uint32_t BDM = (~0U) << (32 - BDB);                       \
584         for (col = x ; col < (x+w) ; col++) {                           \
585             uint32_t spix = *src;                                       \
586             *dst = (((spix << RSS) & RSM & RDM) >> RDS) |               \
587                 (((spix << GSS) & GSM & GDM) >> GDS) |                  \
588                 (((spix << BSS) & BSM & BDM) >> BDS);                   \
589             src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8);   \
590             dst = (DST_T *) ((unsigned long) dst + bpp / 8);            \
591         }                                                               \
592     }
593
594
595 /*
596  * This copies data from the guest framebuffer region, into QEMU's
597  * displaysurface. qemu uses 16 or 32 bpp.  In case the pv framebuffer
598  * uses something else we must convert and copy, otherwise we can
599  * supply the buffer directly and no thing here.
600  */
601 static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
602 {
603     DisplaySurface *surface = qemu_console_surface(xenfb->c.con);
604     int line, oops = 0;
605     int bpp = surface_bits_per_pixel(surface);
606     int linesize = surface_stride(surface);
607     uint8_t *data = surface_data(surface);
608
609     if (!is_buffer_shared(surface)) {
610         switch (xenfb->depth) {
611         case 8:
612             if (bpp == 16) {
613                 BLT(uint8_t, uint16_t,   3, 3, 2,   5, 6, 5);
614             } else if (bpp == 32) {
615                 BLT(uint8_t, uint32_t,   3, 3, 2,   8, 8, 8);
616             } else {
617                 oops = 1;
618             }
619             break;
620         case 24:
621             if (bpp == 16) {
622                 BLT(uint32_t, uint16_t,  8, 8, 8,   5, 6, 5);
623             } else if (bpp == 32) {
624                 BLT(uint32_t, uint32_t,  8, 8, 8,   8, 8, 8);
625             } else {
626                 oops = 1;
627             }
628             break;
629         default:
630             oops = 1;
631         }
632     }
633     if (oops) /* should not happen */
634         xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
635                       __FUNCTION__, xenfb->depth, bpp);
636
637     dpy_gfx_update(xenfb->c.con, x, y, w, h);
638 }
639
640 #ifdef XENFB_TYPE_REFRESH_PERIOD
641 static int xenfb_queue_full(struct XenFB *xenfb)
642 {
643     struct xenfb_page *page = xenfb->c.page;
644     uint32_t cons, prod;
645
646     if (!page)
647         return 1;
648
649     prod = page->in_prod;
650     cons = page->in_cons;
651     return prod - cons == XENFB_IN_RING_LEN;
652 }
653
654 static void xenfb_send_event(struct XenFB *xenfb, union xenfb_in_event *event)
655 {
656     uint32_t prod;
657     struct xenfb_page *page = xenfb->c.page;
658
659     prod = page->in_prod;
660     /* caller ensures !xenfb_queue_full() */
661     xen_mb();                   /* ensure ring space available */
662     XENFB_IN_RING_REF(page, prod) = *event;
663     xen_wmb();                  /* ensure ring contents visible */
664     page->in_prod = prod + 1;
665
666     xen_be_send_notify(&xenfb->c.xendev);
667 }
668
669 static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
670 {
671     union xenfb_in_event event;
672
673     memset(&event, 0, sizeof(event));
674     event.type = XENFB_TYPE_REFRESH_PERIOD;
675     event.refresh_period.period = period;
676     xenfb_send_event(xenfb, &event);
677 }
678 #endif
679
680 /*
681  * Periodic update of display.
682  * Also transmit the refresh interval to the frontend.
683  *
684  * Never ever do any qemu display operations
685  * (resize, screen update) outside this function.
686  * Our screen might be inactive.  When asked for
687  * an update we know it is active.
688  */
689 static void xenfb_update(void *opaque)
690 {
691     struct XenFB *xenfb = opaque;
692     DisplaySurface *surface;
693     int i;
694
695     if (xenfb->c.xendev.be_state != XenbusStateConnected)
696         return;
697
698     if (!xenfb->feature_update) {
699         /* we don't get update notifications, thus use the
700          * sledge hammer approach ... */
701         xenfb->up_fullscreen = 1;
702     }
703
704     /* resize if needed */
705     if (xenfb->do_resize) {
706         pixman_format_code_t format;
707
708         xenfb->do_resize = 0;
709         switch (xenfb->depth) {
710         case 16:
711         case 32:
712             /* console.c supported depth -> buffer can be used directly */
713             format = qemu_default_pixman_format(xenfb->depth, true);
714             surface = qemu_create_displaysurface_from
715                 (xenfb->width, xenfb->height, format,
716                  xenfb->row_stride, xenfb->pixels + xenfb->offset);
717             break;
718         default:
719             /* we must convert stuff */
720             surface = qemu_create_displaysurface(xenfb->width, xenfb->height);
721             break;
722         }
723         dpy_gfx_replace_surface(xenfb->c.con, surface);
724         xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d @ %d bpp%s\n",
725                       xenfb->width, xenfb->height, xenfb->depth,
726                       is_buffer_shared(surface) ? " (shared)" : "");
727         xenfb->up_fullscreen = 1;
728     }
729
730     /* run queued updates */
731     if (xenfb->up_fullscreen) {
732         xen_be_printf(&xenfb->c.xendev, 3, "update: fullscreen\n");
733         xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
734     } else if (xenfb->up_count) {
735         xen_be_printf(&xenfb->c.xendev, 3, "update: %d rects\n", xenfb->up_count);
736         for (i = 0; i < xenfb->up_count; i++)
737             xenfb_guest_copy(xenfb,
738                              xenfb->up_rects[i].x,
739                              xenfb->up_rects[i].y,
740                              xenfb->up_rects[i].w,
741                              xenfb->up_rects[i].h);
742     } else {
743         xen_be_printf(&xenfb->c.xendev, 3, "update: nothing\n");
744     }
745     xenfb->up_count = 0;
746     xenfb->up_fullscreen = 0;
747 }
748
749 static void xenfb_update_interval(void *opaque, uint64_t interval)
750 {
751     struct XenFB *xenfb = opaque;
752
753     if (xenfb->feature_update) {
754 #ifdef XENFB_TYPE_REFRESH_PERIOD
755         if (xenfb_queue_full(xenfb)) {
756             return;
757         }
758         xenfb_send_refresh_period(xenfb, interval);
759 #endif
760     }
761 }
762
763 /* QEMU display state changed, so refresh the framebuffer copy */
764 static void xenfb_invalidate(void *opaque)
765 {
766     struct XenFB *xenfb = opaque;
767     xenfb->up_fullscreen = 1;
768 }
769
770 static void xenfb_handle_events(struct XenFB *xenfb)
771 {
772     uint32_t prod, cons, out_cons;
773     struct xenfb_page *page = xenfb->c.page;
774
775     prod = page->out_prod;
776     out_cons = page->out_cons;
777     if (prod - out_cons > XENFB_OUT_RING_LEN) {
778         return;
779     }
780     xen_rmb();          /* ensure we see ring contents up to prod */
781     for (cons = out_cons; cons != prod; cons++) {
782         union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
783         uint8_t type = event->type;
784         int x, y, w, h;
785
786         switch (type) {
787         case XENFB_TYPE_UPDATE:
788             if (xenfb->up_count == UP_QUEUE)
789                 xenfb->up_fullscreen = 1;
790             if (xenfb->up_fullscreen)
791                 break;
792             x = MAX(event->update.x, 0);
793             y = MAX(event->update.y, 0);
794             w = MIN(event->update.width, xenfb->width - x);
795             h = MIN(event->update.height, xenfb->height - y);
796             if (w < 0 || h < 0) {
797                 xen_be_printf(&xenfb->c.xendev, 1, "bogus update ignored\n");
798                 break;
799             }
800             if (x != event->update.x ||
801                 y != event->update.y ||
802                 w != event->update.width ||
803                 h != event->update.height) {
804                 xen_be_printf(&xenfb->c.xendev, 1, "bogus update clipped\n");
805             }
806             if (w == xenfb->width && h > xenfb->height / 2) {
807                 /* scroll detector: updated more than 50% of the lines,
808                  * don't bother keeping track of the rectangles then */
809                 xenfb->up_fullscreen = 1;
810             } else {
811                 xenfb->up_rects[xenfb->up_count].x = x;
812                 xenfb->up_rects[xenfb->up_count].y = y;
813                 xenfb->up_rects[xenfb->up_count].w = w;
814                 xenfb->up_rects[xenfb->up_count].h = h;
815                 xenfb->up_count++;
816             }
817             break;
818 #ifdef XENFB_TYPE_RESIZE
819         case XENFB_TYPE_RESIZE:
820             if (xenfb_configure_fb(xenfb, xenfb->fb_len,
821                                    event->resize.width,
822                                    event->resize.height,
823                                    event->resize.depth,
824                                    xenfb->fb_len,
825                                    event->resize.offset,
826                                    event->resize.stride) < 0)
827                 break;
828             xenfb_invalidate(xenfb);
829             break;
830 #endif
831         }
832     }
833     xen_mb();           /* ensure we're done with ring contents */
834     page->out_cons = cons;
835 }
836
837 static int fb_init(struct XenDevice *xendev)
838 {
839 #ifdef XENFB_TYPE_RESIZE
840     xenstore_write_be_int(xendev, "feature-resize", 1);
841 #endif
842     return 0;
843 }
844
845 static int fb_initialise(struct XenDevice *xendev)
846 {
847     struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
848     struct xenfb_page *fb_page;
849     int videoram;
850     int rc;
851
852     if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1)
853         videoram = 0;
854
855     rc = common_bind(&fb->c);
856     if (rc != 0)
857         return rc;
858
859     fb_page = fb->c.page;
860     rc = xenfb_configure_fb(fb, videoram * 1024 * 1024U,
861                             fb_page->width, fb_page->height, fb_page->depth,
862                             fb_page->mem_length, 0, fb_page->line_length);
863     if (rc != 0)
864         return rc;
865
866     rc = xenfb_map_fb(fb);
867     if (rc != 0)
868         return rc;
869
870 #if 0  /* handled in xen_init_display() for now */
871     if (!fb->have_console) {
872         fb->c.ds = graphic_console_init(xenfb_update,
873                                         xenfb_invalidate,
874                                         NULL,
875                                         NULL,
876                                         fb);
877         fb->have_console = 1;
878     }
879 #endif
880
881     if (xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update) == -1)
882         fb->feature_update = 0;
883     if (fb->feature_update)
884         xenstore_write_be_int(xendev, "request-update", 1);
885
886     xen_be_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
887                   fb->feature_update, videoram);
888     return 0;
889 }
890
891 static void fb_disconnect(struct XenDevice *xendev)
892 {
893     struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
894
895     /*
896      * FIXME: qemu can't un-init gfx display (yet?).
897      *   Replacing the framebuffer with anonymous shared memory
898      *   instead.  This releases the guest pages and keeps qemu happy.
899      */
900     xenforeignmemory_unmap(xen_fmem, fb->pixels, fb->fbpages);
901     fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
902                       PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
903                       -1, 0);
904     if (fb->pixels == MAP_FAILED) {
905         xen_be_printf(xendev, 0,
906                 "Couldn't replace the framebuffer with anonymous memory errno=%d\n",
907                 errno);
908     }
909     common_unbind(&fb->c);
910     fb->feature_update = 0;
911     fb->bug_trigger    = 0;
912 }
913
914 static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
915 {
916     struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
917
918     /*
919      * Set state to Connected *again* once the frontend switched
920      * to connected.  We must trigger the watch a second time to
921      * workaround a frontend bug.
922      */
923     if (fb->bug_trigger == 0 && strcmp(node, "state") == 0 &&
924         xendev->fe_state == XenbusStateConnected &&
925         xendev->be_state == XenbusStateConnected) {
926         xen_be_printf(xendev, 2, "re-trigger connected (frontend bug)\n");
927         xen_be_set_state(xendev, XenbusStateConnected);
928         fb->bug_trigger = 1; /* only once */
929     }
930 }
931
932 static void fb_event(struct XenDevice *xendev)
933 {
934     struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
935
936     xenfb_handle_events(xenfb);
937     xen_be_send_notify(&xenfb->c.xendev);
938 }
939
940 /* -------------------------------------------------------------------- */
941
942 struct XenDevOps xen_kbdmouse_ops = {
943     .size       = sizeof(struct XenInput),
944     .init       = input_init,
945     .initialise = input_initialise,
946     .connected  = input_connected,
947     .disconnect = input_disconnect,
948     .event      = input_event,
949 };
950
951 struct XenDevOps xen_framebuffer_ops = {
952     .size       = sizeof(struct XenFB),
953     .init       = fb_init,
954     .initialise = fb_initialise,
955     .disconnect = fb_disconnect,
956     .event      = fb_event,
957     .frontend_changed = fb_frontend_changed,
958 };
959
960 static const GraphicHwOps xenfb_ops = {
961     .invalidate  = xenfb_invalidate,
962     .gfx_update  = xenfb_update,
963     .update_interval = xenfb_update_interval,
964 };
965
966 /*
967  * FIXME/TODO: Kill this.
968  * Temporary needed while DisplayState reorganization is in flight.
969  */
970 void xen_init_display(int domid)
971 {
972     struct XenDevice *xfb, *xin;
973     struct XenFB *fb;
974     struct XenInput *in;
975     int i = 0;
976
977 wait_more:
978     i++;
979     main_loop_wait(true);
980     xfb = xen_be_find_xendev("vfb", domid, 0);
981     xin = xen_be_find_xendev("vkbd", domid, 0);
982     if (!xfb || !xin) {
983         if (i < 256) {
984             usleep(10000);
985             goto wait_more;
986         }
987         xen_be_printf(NULL, 1, "displaystate setup failed\n");
988         return;
989     }
990
991     /* vfb */
992     fb = container_of(xfb, struct XenFB, c.xendev);
993     fb->c.con = graphic_console_init(NULL, 0, &xenfb_ops, fb);
994     fb->have_console = 1;
995
996     /* vkbd */
997     in = container_of(xin, struct XenInput, c.xendev);
998     in->c.con = fb->c.con;
999
1000     /* retry ->init() */
1001     xen_be_check_state(xin);
1002     xen_be_check_state(xfb);
1003 }
This page took 0.079965 seconds and 4 git commands to generate.