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